From fb74df8f817dfa4377d74218d60d3bdfef9f074f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sat, 20 Jun 2020 11:57:55 +0200 Subject: [PATCH 01/54] Start integrating zigbee into nymea --- .../zigbeehardwareresourceimplementation.cpp | 123 ++++++++++++++++++ .../zigbeehardwareresourceimplementation.h | 73 +++++++++++ .../hardwaremanagerimplementation.cpp | 8 ++ libnymea-core/hardwaremanagerimplementation.h | 4 +- libnymea-core/jsonrpc/zigbeehandler.cpp | 74 +++++++++++ libnymea-core/jsonrpc/zigbeehandler.h | 56 ++++++++ libnymea-core/libnymea-core.pro | 12 +- libnymea-core/nymeacore.cpp | 8 ++ libnymea-core/nymeacore.h | 5 + libnymea-core/zigbee/zigbeemanager.cpp | 50 +++++++ libnymea-core/zigbee/zigbeemanager.h | 60 +++++++++ .../hardware/zigbee/zigbeehardwarereource.cpp | 37 ++++++ .../hardware/zigbee/zigbeehardwarereource.h | 49 +++++++ libnymea/hardwaremanager.h | 2 + libnymea/libnymea.pro | 2 + libnymea/loggingcategories.h | 2 + 16 files changed, 561 insertions(+), 4 deletions(-) create mode 100644 libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp create mode 100644 libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h create mode 100644 libnymea-core/jsonrpc/zigbeehandler.cpp create mode 100644 libnymea-core/jsonrpc/zigbeehandler.h create mode 100644 libnymea-core/zigbee/zigbeemanager.cpp create mode 100644 libnymea-core/zigbee/zigbeemanager.h create mode 100644 libnymea/hardware/zigbee/zigbeehardwarereource.cpp create mode 100644 libnymea/hardware/zigbee/zigbeehardwarereource.h diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp new file mode 100644 index 00000000..3a3974c5 --- /dev/null +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -0,0 +1,123 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 "zigbeemanagerimplementation.h" +#include "loggingcategories.h" +#include "nymeasettings.h" + +#include +#include + +#include "nymea-zigbee/zigbeenetworkmanager.h" + +namespace nymeaserver { + +ZigbeeHardwareResourceImplementation::ZigbeeHardwareResourceImplementation(QObject *parent) : + ZigbeeHardwareResource(parent) +{ + +} + +bool ZigbeeHardwareResourceImplementation::available() const +{ + return m_available; +} + +bool ZigbeeHardwareResourceImplementation::enabled() const +{ + return m_enabled; +} + +void ZigbeeHardwareResourceImplementation::setZigbeeNetwork(ZigbeeNetwork *network) +{ + // Clean up + if (m_zigbeeNetwork) { + disconnect(m_zigbeeNetwork, &ZigbeeNetwork::stateChanged, this, &ZigbeeHardwareResourceImplementation::onZigbeeNetworkStateChanged); + } + + // Set new network + m_zigbeeNetwork = network; + connect(m_zigbeeNetwork, &ZigbeeNetwork::stateChanged, this, &ZigbeeHardwareResourceImplementation::onZigbeeNetworkStateChanged); +} + +void ZigbeeHardwareResourceImplementation::setEnabled(bool enabled) +{ + qCDebug(dcZigbeeHardwareResource()) << "Set" << (enabled ? "enabled" : "disabled"); + if (m_enabled && enabled) { + qCDebug(dcZigbeeHardwareResource()) << "Already enabled."; + return; + } else if (!m_enabled && !enabled) { + qCDebug(dcZigbeeHardwareResource()) << "Already disabled."; + return; + } + + bool success = false; + if (enabled) { + success = enable(); + } else { + success = disable(); + } + + if (success) { + m_enabled = enabled; + emit enabledChanged(m_enabled); + } +} + +void ZigbeeHardwareResourceImplementation::onZigbeeNetworkStateChanged(ZigbeeNetwork::State state) +{ + qCDebug(dcZigbeeHardwareResource()) << "Network state changed" << state; +} + +bool ZigbeeHardwareResourceImplementation::enable() +{ + qCDebug(dcZigbeeHardwareResource()) << "Enable hardware resource"; + + if (!m_zigbeeNetwork) { + qCDebug(dcZigbeeHardwareResource()) << "There is no zigbee network configured as hardware resource"; + } else { + // TODO: start network + } + + return true; +} + +bool ZigbeeHardwareResourceImplementation::disable() +{ + qCDebug(dcZigbeeHardwareResource()) << "Disable hardware resource"; + if (!m_zigbeeNetwork) { + qCDebug(dcZigbeeHardwareResource()) << "There is no zigbee network configured as hardware resource"; + } + + // TODO: stop network + return true; +} + +} diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h new file mode 100644 index 00000000..ab29f96b --- /dev/null +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h @@ -0,0 +1,73 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 ZIGBEEHARDWARERESOURCEIMPLEMENTATION_H +#define ZIGBEEHARDWARERESOURCEIMPLEMENTATION_H + +#include + +#include "zigbeenetwork.h" +#include "hardware/zigbee/zigbeehardwarereource.h" + +namespace nymeaserver { + +class ZigbeeHardwareResourceImplementation : public ZigbeeHardwareResource +{ + Q_OBJECT + +public: + explicit ZigbeeHardwareResourceImplementation(QObject *parent = nullptr); + + bool available() const override; + bool enabled() const override; + + void setZigbeeNetwork(ZigbeeNetwork *network); + +private: + bool m_available = false; + bool m_enabled = false; + + ZigbeeNetwork *m_zigbeeNetwork = nullptr; + +protected: + void setEnabled(bool enabled) override; + +private slots: + void onZigbeeNetworkStateChanged(ZigbeeNetwork::State state); + +public slots: + bool enable(); + bool disable(); + +}; + +} + +#endif // ZIGBEEHARDWARERESOURCEIMPLEMENTATION_H diff --git a/libnymea-core/hardwaremanagerimplementation.cpp b/libnymea-core/hardwaremanagerimplementation.cpp index 7e057cf0..6a804dcb 100644 --- a/libnymea-core/hardwaremanagerimplementation.cpp +++ b/libnymea-core/hardwaremanagerimplementation.cpp @@ -42,6 +42,7 @@ #include "hardware/bluetoothlowenergy/bluetoothlowenergymanagerimplementation.h" #include "hardware/network/mqtt/mqttproviderimplementation.h" #include "hardware/i2c/i2cmanagerimplementation.h" +#include "hardware/zigbee/zigbeehardwareresourceimplementation.h" namespace nymeaserver { @@ -70,6 +71,8 @@ HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform, m_i2cManager = new I2CManagerImplementation(this); + m_zigbeeManager = new ZigbeeHardwareResourceImplementation(this); + qCDebug(dcHardware()) << "Hardware manager initialized successfully"; @@ -136,4 +139,9 @@ I2CManager *HardwareManagerImplementation::i2cManager() return m_i2cManager; } +ZigbeeHardwareResource *HardwareManagerImplementation::zigbeeManager() +{ + return m_zigbeeManager; +} + } diff --git a/libnymea-core/hardwaremanagerimplementation.h b/libnymea-core/hardwaremanagerimplementation.h index 0c5899eb..3094d3d0 100644 --- a/libnymea-core/hardwaremanagerimplementation.h +++ b/libnymea-core/hardwaremanagerimplementation.h @@ -57,7 +57,8 @@ public: PlatformZeroConfController *zeroConfController() override; BluetoothLowEnergyManager *bluetoothLowEnergyManager() override; MqttProvider *mqttProvider() override; - I2CManager * i2cManager() override; + I2CManager *i2cManager() override; + ZigbeeHardwareResource *zigbeeManager() override; private: QNetworkAccessManager *m_networkAccessManager = nullptr; @@ -72,6 +73,7 @@ private: BluetoothLowEnergyManager *m_bluetoothLowEnergyManager = nullptr; MqttProvider *m_mqttProvider = nullptr; I2CManager *m_i2cManager = nullptr; + ZigbeeHardwareResource *m_zigbeeManager = nullptr; }; } diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp new file mode 100644 index 00000000..46387a8f --- /dev/null +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -0,0 +1,74 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "zigbeehandler.h" + +namespace nymeaserver { + +ZigbeeHandler::ZigbeeHandler(QObject *parent) : + JsonHandler(parent) +{ + registerEnum(); + registerEnum(); + + QVariantMap params, returns; + QString description; + + params.clear(); returns.clear(); + description = "Get the status of the current network."; + returns.insert("available", enumValueName(Bool)); + returns.insert("enabled", enumValueName(Bool)); + returns.insert("configured", enumValueName(Bool)); + returns.insert("state", enumRef()); + registerMethod("GetNetworkStatus", description, params, returns); + + + // GetUartInterfaces + params.clear(); returns.clear(); + description = "Get the available UART interfaces in order to set up the zigbee network on the approriate serial interface."; + returns.insert("available", enumValueName(Bool)); + returns.insert("enabled", enumValueName(Bool)); + returns.insert("configured", enumValueName(Bool)); + returns.insert("state", enumRef()); + registerMethod("GetUartInterfaces", description, params, returns); + + + // Setup network, uart, baudrate, backendtype + + + +} + +QString ZigbeeHandler::name() const +{ + return "Zigbee"; +} + +} diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h new file mode 100644 index 00000000..d0ce3786 --- /dev/null +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -0,0 +1,56 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 ZIGBEEHANDLER_H +#define ZIGBEEHANDLER_H + +#include + +#include "jsonrpc/jsonhandler.h" + +#include + +namespace nymeaserver { + +class ZigbeeHandler : public JsonHandler +{ + Q_OBJECT +public: + explicit ZigbeeHandler(QObject *parent = nullptr); + + QString name() const override; + +signals: + +}; + +} + +#endif // ZIGBEEHANDLER_H diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 0b00372f..f27cf711 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -8,7 +8,7 @@ INCLUDEPATH += $$top_srcdir/libnymea $$top_builddir LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto CONFIG += link_pkgconfig -PKGCONFIG += nymea-mqtt nymea-networkmanager +PKGCONFIG += nymea-mqtt nymea-networkmanager nymea-zigbee # As of Ubuntu focal, there's a commonly named python3-embed pointing to the distro version of python # For everything below python 3.8 we need to manually select one @@ -37,6 +37,7 @@ RESOURCES += $$top_srcdir/icons.qrc \ HEADERS += nymeacore.h \ integrations/apikeysprovidersloader.h \ + hardware/zigbee/zigbeehardwareresourceimplementation.h \ integrations/plugininfocache.h \ integrations/python/pynymealogginghandler.h \ integrations/python/pynymeamodule.h \ @@ -53,6 +54,7 @@ HEADERS += nymeacore.h \ integrations/translator.h \ integrations/pythonintegrationplugin.h \ experiences/experiencemanager.h \ + jsonrpc/zigbeehandler.h \ ruleengine/ruleengine.h \ ruleengine/rule.h \ ruleengine/stateevaluator.h \ @@ -126,16 +128,19 @@ HEADERS += nymeacore.h \ tagging/tag.h \ cloud/cloudtransport.h \ debugreportgenerator.h \ - platform/platform.h \ + platform/platform.h \ \ + zigbee/zigbeemanager.h SOURCES += nymeacore.cpp \ integrations/apikeysprovidersloader.cpp \ + hardware/zigbee/zigbeehardwareresourceimplementation.cpp \ integrations/plugininfocache.cpp \ integrations/thingmanagerimplementation.cpp \ integrations/translator.cpp \ integrations/pythonintegrationplugin.cpp \ experiences/experiencemanager.cpp \ + jsonrpc/zigbeehandler.cpp \ ruleengine/ruleengine.cpp \ ruleengine/rule.cpp \ ruleengine/stateevaluator.cpp \ @@ -208,7 +213,8 @@ SOURCES += nymeacore.cpp \ tagging/tag.cpp \ cloud/cloudtransport.cpp \ debugreportgenerator.cpp \ - platform/platform.cpp \ + platform/platform.cpp \ \ + zigbee/zigbeemanager.cpp versionAtLeast(QT_VERSION, 5.12.0) { diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index 48c144c1..33f94b9b 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -106,6 +106,9 @@ void NymeaCore::init() { qCDebug(dcCore) << "Creating Server Manager"; m_serverManager = new ServerManager(m_platform, m_configuration, this); + qCDebug(dcCore()) << "Create Zigbee Manager"; + m_zigbeeManager = new ZigbeeManager(this); + qCDebug(dcCore) << "Creating Hardware Manager"; m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), this); @@ -649,6 +652,11 @@ Platform *NymeaCore::platform() const return m_platform; } +ZigbeeManager *NymeaCore::zigbeeManager() const +{ + return m_zigbeeManager; +} + void NymeaCore::gotEvent(const Event &event) { m_logger->logEvent(event); diff --git a/libnymea-core/nymeacore.h b/libnymea-core/nymeacore.h index c49e4956..364de311 100644 --- a/libnymea-core/nymeacore.h +++ b/libnymea-core/nymeacore.h @@ -46,6 +46,8 @@ #include "time/timemanager.h" #include "hardwaremanagerimplementation.h" +#include "zigbee/zigbeemanager.h" + #include "debugserverhandler.h" #include @@ -66,6 +68,7 @@ class System; class ExperienceManager; class ScriptEngine; class CloudManager; +class ZigbeeManager; class NymeaCore : public QObject { @@ -106,6 +109,7 @@ public: DebugServerHandler *debugServerHandler() const; TagsStorage *tagsStorage() const; Platform *platform() const; + ZigbeeManager *zigbeeManager() const; static QStringList getAvailableLanguages(); static QStringList loggingFilters(); @@ -149,6 +153,7 @@ private: UserManager *m_userManager; System *m_system; ExperienceManager *m_experienceManager; + ZigbeeManager *m_zigbeeManager; QList m_executingRules; diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp new file mode 100644 index 00000000..562a8bc7 --- /dev/null +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -0,0 +1,50 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 "zigbeemanager.h" + +namespace nymeaserver { + +ZigbeeManager::ZigbeeManager(QObject *parent) : QObject(parent) +{ + +} + +bool ZigbeeManager::available() const +{ + return m_zigbeeNetwork != nullptr; +} + +void ZigbeeManager::setupNetwork(const QString serialPort, qint32 baudrate, ZigbeeNetworkManager::BackendType) +{ + +} + +} diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h new file mode 100644 index 00000000..ed871fbc --- /dev/null +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 ZIGBEEMANAGER_H +#define ZIGBEEMANAGER_H + +#include + +#include + +namespace nymeaserver { + +class ZigbeeManager : public QObject +{ + Q_OBJECT +public: + explicit ZigbeeManager(QObject *parent = nullptr); + + bool available() const; + + void setupNetwork(const QString serialPort, qint32 baudrate, ZigbeeNetworkManager::BackendType); + +private: + ZigbeeNetwork *m_zigbeeNetwork = nullptr; + +signals: + void zigbeeNetworkChanged(ZigbeeNetwork *zigbeeNetwork); + +}; + +} + +#endif // ZIGBEEMANAGER_H diff --git a/libnymea/hardware/zigbee/zigbeehardwarereource.cpp b/libnymea/hardware/zigbee/zigbeehardwarereource.cpp new file mode 100644 index 00000000..c1e5bfd4 --- /dev/null +++ b/libnymea/hardware/zigbee/zigbeehardwarereource.cpp @@ -0,0 +1,37 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "zigbeehardwarereource.h" + +ZigbeeHardwareResource::ZigbeeHardwareResource(QObject *parent) : + HardwareResource("Zigbee hardware resource", parent) +{ + +} diff --git a/libnymea/hardware/zigbee/zigbeehardwarereource.h b/libnymea/hardware/zigbee/zigbeehardwarereource.h new file mode 100644 index 00000000..f97fcb56 --- /dev/null +++ b/libnymea/hardware/zigbee/zigbeehardwarereource.h @@ -0,0 +1,49 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 ZIGBEEHARDWARERESOURCE_H +#define ZIGBEEHARDWARERESOURCE_H + +#include + +#include "hardwareresource.h" + +class ZigbeeHardwareResource : public HardwareResource +{ + Q_OBJECT +public: + explicit ZigbeeHardwareResource(QObject *parent = nullptr); + virtual ~ZigbeeHardwareResource() = default; + + + +}; + +#endif // ZIGBEEHARDWARERESOURCE_H diff --git a/libnymea/hardwaremanager.h b/libnymea/hardwaremanager.h index d5ed2c45..2e384d90 100644 --- a/libnymea/hardwaremanager.h +++ b/libnymea/hardwaremanager.h @@ -42,6 +42,7 @@ class PlatformZeroConfController; class BluetoothLowEnergyManager; class MqttProvider; class I2CManager; +class ZigbeeHardwareResource; class HardwareResource; class HardwareManager : public QObject @@ -61,6 +62,7 @@ public: virtual BluetoothLowEnergyManager *bluetoothLowEnergyManager() = 0; virtual MqttProvider *mqttProvider() = 0; virtual I2CManager *i2cManager() = 0; + virtual ZigbeeHardwareResource *zigbeeManager() = 0; protected: void setResourceEnabled(HardwareResource* resource, bool enabled); diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index b86c15e8..a5fb1ba4 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -10,6 +10,7 @@ DEFINES += LIBNYMEA_LIBRARY QMAKE_LFLAGS += -fPIC HEADERS += \ + hardware/zigbee/zigbeehardwarereource.h \ integrations/browseractioninfo.h \ integrations/browseritemactioninfo.h \ integrations/browseritemresult.h \ @@ -102,6 +103,7 @@ HEADERS += \ experiences/experienceplugin.h \ SOURCES += \ + hardware/zigbee/zigbeehardwarereource.cpp \ integrations/browseractioninfo.cpp \ integrations/browseritemactioninfo.cpp \ integrations/browseritemresult.cpp \ diff --git a/libnymea/loggingcategories.h b/libnymea/loggingcategories.h index dfb88212..979173fb 100644 --- a/libnymea/loggingcategories.h +++ b/libnymea/loggingcategories.h @@ -91,6 +91,8 @@ Q_DECLARE_LOGGING_CATEGORY(dcCoap) Q_DECLARE_LOGGING_CATEGORY(dcI2C) Q_DECLARE_LOGGING_CATEGORY(dcIntegrations) Q_DECLARE_LOGGING_CATEGORY(dcJsIntegrations) +Q_DECLARE_LOGGING_CATEGORY(dcZigbee) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeHardwareResource) /* From 7cb995767cf27585c71e82db89ea9013d1ed5301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 29 Jun 2020 13:11:53 +0200 Subject: [PATCH 02/54] Add zigbee serial port for api --- .../zigbeehardwareresourceimplementation.cpp | 2 +- libnymea-core/jsonrpc/zigbeehandler.cpp | 82 ++++++++++++++++--- libnymea-core/jsonrpc/zigbeehandler.h | 11 ++- libnymea-core/libnymea-core.pro | 8 +- libnymea-core/zigbee/zigbeemanager.cpp | 55 ++++++++++++- libnymea-core/zigbee/zigbeemanager.h | 9 +- libnymea-core/zigbee/zigbeeserialport.cpp | 80 ++++++++++++++++++ libnymea-core/zigbee/zigbeeserialport.h | 77 +++++++++++++++++ 8 files changed, 307 insertions(+), 17 deletions(-) create mode 100644 libnymea-core/zigbee/zigbeeserialport.cpp create mode 100644 libnymea-core/zigbee/zigbeeserialport.h diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index 3a3974c5..802977ed 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -28,7 +28,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "zigbeemanagerimplementation.h" +#include "zigbeehardwareresourceimplementation.h" #include "loggingcategories.h" #include "nymeasettings.h" diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 46387a8f..c9481ac1 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -29,40 +29,70 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "zigbeehandler.h" +#include "zigbee/zigbeemanager.h" namespace nymeaserver { -ZigbeeHandler::ZigbeeHandler(QObject *parent) : - JsonHandler(parent) +ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : + JsonHandler(parent), + m_zigbeeManager(zigbeeManager) { registerEnum(); registerEnum(); + registerObject(); + registerObject(); + QVariantMap params, returns; QString description; + /* 1. GetNetworkStatus + * 2. Setup network if the is no network configured + * - GetUartInterfaces + * - Setup network with given UART interface and backend type + * - + */ + params.clear(); returns.clear(); description = "Get the status of the current network."; returns.insert("available", enumValueName(Bool)); returns.insert("enabled", enumValueName(Bool)); returns.insert("configured", enumValueName(Bool)); - returns.insert("state", enumRef()); + returns.insert("serialPort", enumValueName(String)); + returns.insert("baudRate", enumValueName(Uint)); + returns.insert("backend", enumRef()); + returns.insert("firmwareVersion", enumValueName(String)); + returns.insert("networkIeeeeAddress", enumValueName(String)); + returns.insert("networkPanId", enumValueName(Uint)); + returns.insert("channel", enumValueName(Uint)); + returns.insert("permitJoin", enumValueName(Bool)); + returns.insert("networkState", enumRef()); registerMethod("GetNetworkStatus", description, params, returns); - // GetUartInterfaces params.clear(); returns.clear(); description = "Get the available UART interfaces in order to set up the zigbee network on the approriate serial interface."; - returns.insert("available", enumValueName(Bool)); - returns.insert("enabled", enumValueName(Bool)); - returns.insert("configured", enumValueName(Bool)); - returns.insert("state", enumRef()); + returns.insert("uartInterfaces", objectRef()); registerMethod("GetUartInterfaces", description, params, returns); + // GetNetworkStatus + // NetworkStatusChanged + // SetupNetwork(network, uart, baudrate, backendtype) + // PermitJoin(time, o:nwk address) + // FactoryResetNetwork - // Setup network, uart, baudrate, backendtype - + // GetNodes [Node(mac, nwkAddress, name, manufacturer, type, descriptors, associacted device, state, reachable)] + // NodeAdded + // NodeChanged (state, node base information, associated deviceId) + // RemoveNode + // NodeRemoved + // GetGroups + // GroupChanged + // AddGroup + // GroupAdded + // RemoveGroup + // GroupRemoved } @@ -71,4 +101,36 @@ QString ZigbeeHandler::name() const return "Zigbee"; } +JsonReply *ZigbeeHandler::GetNetworkStatus(const QVariantMap ¶ms) +{ + Q_UNUSED(params) + + QVariantMap ret; +// if (m_zigbeeManager->zigbeeNetwork()) { +// ret.insert("available", m_zigbeeManager->available()); +// ret.insert("enabled", m_zigbeeManager->enabled()); +// ret.insert("configured", true); +// ret.insert("networkState", m_zigbeeManager->zigbeeNetwork()->state()); +// } else { +// ret.insert("available", m_zigbeeManager->available()); +// ret.insert("enabled", m_zigbeeManager->enabled()); +// ret.insert("configured", false); +// ret.insert("state", ZigbeeNetwork::StateUninitialized); +// } + + return createReply(ret); +} + +JsonReply *ZigbeeHandler::GetUartInterfaces(const QVariantMap ¶ms) +{ + Q_UNUSED(params) + QVariantMap ret; + QVariantList portList; + foreach (const ZigbeeSerialPort &serialPort, m_zigbeeManager->availablePorts()) { + portList << pack(serialPort); + } + ret.insert("uartInterfaces", portList); + return createReply(ret); +} + } diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h index d0ce3786..7b4b502e 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.h +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -39,14 +39,23 @@ namespace nymeaserver { +class ZigbeeManager; + class ZigbeeHandler : public JsonHandler { Q_OBJECT public: - explicit ZigbeeHandler(QObject *parent = nullptr); + explicit ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent = nullptr); QString name() const override; + Q_INVOKABLE JsonReply *GetNetworkStatus(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetUartInterfaces(const QVariantMap ¶ms); + + +private: + ZigbeeManager *m_zigbeeManager = nullptr; + signals: }; diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index f27cf711..74b8f417 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -3,7 +3,7 @@ TARGET = nymea-core include(../nymea.pri) -QT += sql qml +QT += sql qml serialport INCLUDEPATH += $$top_srcdir/libnymea $$top_builddir LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto @@ -129,7 +129,8 @@ HEADERS += nymeacore.h \ cloud/cloudtransport.h \ debugreportgenerator.h \ platform/platform.h \ \ - zigbee/zigbeemanager.h + zigbee/zigbeemanager.h \ + zigbee/zigbeeserialport.h SOURCES += nymeacore.cpp \ @@ -214,7 +215,8 @@ SOURCES += nymeacore.cpp \ cloud/cloudtransport.cpp \ debugreportgenerator.cpp \ platform/platform.cpp \ \ - zigbee/zigbeemanager.cpp + zigbee/zigbeemanager.cpp \ + zigbee/zigbeeserialport.cpp versionAtLeast(QT_VERSION, 5.12.0) { diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 562a8bc7..701b8a7e 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -29,6 +29,10 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "zigbeemanager.h" +#include "nymeasettings.h" +#include "loggingcategories.h" + +#include namespace nymeaserver { @@ -42,9 +46,58 @@ bool ZigbeeManager::available() const return m_zigbeeNetwork != nullptr; } -void ZigbeeManager::setupNetwork(const QString serialPort, qint32 baudrate, ZigbeeNetworkManager::BackendType) +bool ZigbeeManager::enabled() const { + return m_zigbeeNetwork && m_zigbeeNetwork->state() != ZigbeeNetwork::StateUninitialized; +} +ZigbeeNetwork *ZigbeeManager::zigbeeNetwork() const +{ + return m_zigbeeNetwork; +} + +ZigbeeSerialPortList ZigbeeManager::availablePorts() +{ + ZigbeeSerialPortList ports; + foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { + qCDebug(dcZigbee()) << "Found serial port" << serialPortInfo.portName(); + qCDebug(dcZigbee()) << " Description:" << serialPortInfo.description(); + qCDebug(dcZigbee()) << " System location:" << serialPortInfo.systemLocation(); + qCDebug(dcZigbee()) << " Manufacturer:" << serialPortInfo.manufacturer(); + qCDebug(dcZigbee()) << " Serialnumber:" << serialPortInfo.serialNumber(); + + if (serialPortInfo.hasProductIdentifier()) { + qCDebug(dcZigbee()) << " Product identifier:" << serialPortInfo.productIdentifier(); + } + if (serialPortInfo.hasVendorIdentifier()) { + qCDebug(dcZigbee()) << " Vendor identifier:" << serialPortInfo.vendorIdentifier(); + } + + ZigbeeSerialPort port; + port.setName(serialPortInfo.portName()); + port.setDescription(serialPortInfo.description()); + port.setSystemLocation(serialPortInfo.systemLocation()); + ports.append(port); + } + + return ports; +} + +void ZigbeeManager::createZigbeeNetwork(const QString &serialPort, qint32 baudrate, ZigbeeNetworkManager::BackendType backend) +{ + if (m_zigbeeNetwork) { + delete m_zigbeeNetwork; + m_zigbeeNetwork = nullptr; + } + + m_zigbeeNetwork = ZigbeeNetworkManager::createZigbeeNetwork(backend, this); + m_zigbeeNetwork->setSerialPortName(serialPort); + m_zigbeeNetwork->setSerialBaudrate(baudrate); + m_zigbeeNetwork->setSettingsFileName(NymeaSettings(NymeaSettings::SettingsRoleGlobal).fileName()); + + m_zigbeeNetwork->startNetwork(); + + emit zigbeeNetworkChanged(m_zigbeeNetwork); } } diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index ed871fbc..02ab7ad4 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -35,6 +35,8 @@ #include +#include "zigbeeserialport.h" + namespace nymeaserver { class ZigbeeManager : public QObject @@ -44,8 +46,13 @@ public: explicit ZigbeeManager(QObject *parent = nullptr); bool available() const; + bool enabled() const; - void setupNetwork(const QString serialPort, qint32 baudrate, ZigbeeNetworkManager::BackendType); + ZigbeeNetwork *zigbeeNetwork() const; + + ZigbeeSerialPortList availablePorts(); + + void createZigbeeNetwork(const QString &serialPort, qint32 baudrate, ZigbeeNetworkManager::BackendType backend); private: ZigbeeNetwork *m_zigbeeNetwork = nullptr; diff --git a/libnymea-core/zigbee/zigbeeserialport.cpp b/libnymea-core/zigbee/zigbeeserialport.cpp new file mode 100644 index 00000000..6b2b12d7 --- /dev/null +++ b/libnymea-core/zigbee/zigbeeserialport.cpp @@ -0,0 +1,80 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 "zigbeeserialport.h" + +namespace nymeaserver { + +ZigbeeSerialPort::ZigbeeSerialPort() +{ + +} + +QString ZigbeeSerialPort::name() const +{ + return m_name; +} + +void ZigbeeSerialPort::setName(const QString &name) +{ + m_name = name; +} + +QString ZigbeeSerialPort::description() const +{ + return m_description; +} + +void ZigbeeSerialPort::setDescription(const QString &description) +{ + m_description = description; +} + +QString ZigbeeSerialPort::systemLocation() const +{ + return m_systemLocation; +} + +void ZigbeeSerialPort::setSystemLocation(const QString &systemLocation) +{ + m_systemLocation = systemLocation; +} + +QVariant ZigbeeSerialPortList::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void ZigbeeSerialPortList::put(const QVariant &variant) +{ + append(variant.value()); +} + +} diff --git a/libnymea-core/zigbee/zigbeeserialport.h b/libnymea-core/zigbee/zigbeeserialport.h new file mode 100644 index 00000000..34397bec --- /dev/null +++ b/libnymea-core/zigbee/zigbeeserialport.h @@ -0,0 +1,77 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 ZIGBEESERIALPORT_H +#define ZIGBEESERIALPORT_H + +#include +#include +namespace nymeaserver { + +class ZigbeeSerialPort +{ + Q_GADGET + Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString description READ description) + Q_PROPERTY(QString systemLocation READ systemLocation) + +public: + ZigbeeSerialPort(); + + QString name() const; + void setName(const QString &name); + + QString description() const; + void setDescription(const QString &description); + + QString systemLocation() const; + void setSystemLocation(const QString &systemLocation); + +private: + QString m_name; + QString m_description; + QString m_systemLocation; +}; + +class ZigbeeSerialPortList: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; + +} + +Q_DECLARE_METATYPE(nymeaserver::ZigbeeSerialPort) +Q_DECLARE_METATYPE(nymeaserver::ZigbeeSerialPortList) + +#endif // ZIGBEESERIALPORT_H From 9052472150496ec1970a75ded7628e72c32d8fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 27 Oct 2020 09:06:58 +0100 Subject: [PATCH 03/54] Sort source and header file for core lib --- libnymea-core/libnymea-core.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 74b8f417..1a23e33a 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -123,6 +123,7 @@ HEADERS += nymeacore.h \ hardware/network/mqtt/mqttproviderimplementation.h \ hardware/network/mqtt/mqttchannelimplementation.h \ hardware/i2c/i2cmanagerimplementation.h \ + hardware/zigbee/zigbeehardwareresourceimplementation.h \ debugserverhandler.h \ tagging/tagsstorage.h \ tagging/tag.h \ @@ -209,6 +210,7 @@ SOURCES += nymeacore.cpp \ hardware/network/mqtt/mqttproviderimplementation.cpp \ hardware/network/mqtt/mqttchannelimplementation.cpp \ hardware/i2c/i2cmanagerimplementation.cpp \ + hardware/zigbee/zigbeehardwareresourceimplementation.cpp \ debugserverhandler.cpp \ tagging/tagsstorage.cpp \ tagging/tag.cpp \ From 228a4f9f9c20f6c89abaf86042c9dff335084ba7 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 27 Oct 2020 10:54:37 +0100 Subject: [PATCH 04/54] fixx da build --- .../hardware/zigbee/zigbeehardwareresourceimplementation.cpp | 2 +- libnymea-core/jsonrpc/zigbeehandler.h | 2 +- libnymea-core/libnymea-core.pro | 2 +- libnymea-core/zigbee/zigbeemanager.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index 802977ed..edf1172b 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -35,7 +35,7 @@ #include #include -#include "nymea-zigbee/zigbeenetworkmanager.h" +#include namespace nymeaserver { diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h index 7b4b502e..376eb24f 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.h +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -35,7 +35,7 @@ #include "jsonrpc/jsonhandler.h" -#include +#include namespace nymeaserver { diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 1a23e33a..b940c5dc 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -216,7 +216,7 @@ SOURCES += nymeacore.cpp \ tagging/tag.cpp \ cloud/cloudtransport.cpp \ debugreportgenerator.cpp \ - platform/platform.cpp \ \ + platform/platform.cpp \ zigbee/zigbeemanager.cpp \ zigbee/zigbeeserialport.cpp diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index 02ab7ad4..54a4a652 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -33,7 +33,7 @@ #include -#include +#include #include "zigbeeserialport.h" From 0f0b903af8a04b89c26b9151f7bf7155b0036013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 28 Oct 2020 09:45:38 +0100 Subject: [PATCH 05/54] Clean up source and dependencies and make build against libnymea-zigbee --- libnymea-core/jsonrpc/zigbeehandler.cpp | 26 ++++---- libnymea-core/libnymea-core.pro | 6 +- libnymea-core/zigbee/zigbeemanager.cpp | 29 +------- libnymea-core/zigbee/zigbeemanager.h | 6 +- libnymea-core/zigbee/zigbeeserialport.cpp | 80 ----------------------- libnymea-core/zigbee/zigbeeserialport.h | 77 ---------------------- libnymea/loggingcategories.cpp | 1 + 7 files changed, 18 insertions(+), 207 deletions(-) delete mode 100644 libnymea-core/zigbee/zigbeeserialport.cpp delete mode 100644 libnymea-core/zigbee/zigbeeserialport.h diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index c9481ac1..8a6ab354 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -38,10 +38,10 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : m_zigbeeManager(zigbeeManager) { registerEnum(); - registerEnum(); + registerEnum(); - registerObject(); - registerObject(); +// registerObject(); +// registerObject(); QVariantMap params, returns; QString description; @@ -60,7 +60,7 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : returns.insert("configured", enumValueName(Bool)); returns.insert("serialPort", enumValueName(String)); returns.insert("baudRate", enumValueName(Uint)); - returns.insert("backend", enumRef()); + returns.insert("backend", enumRef()); returns.insert("firmwareVersion", enumValueName(String)); returns.insert("networkIeeeeAddress", enumValueName(String)); returns.insert("networkPanId", enumValueName(Uint)); @@ -70,10 +70,10 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : registerMethod("GetNetworkStatus", description, params, returns); // GetUartInterfaces - params.clear(); returns.clear(); - description = "Get the available UART interfaces in order to set up the zigbee network on the approriate serial interface."; - returns.insert("uartInterfaces", objectRef()); - registerMethod("GetUartInterfaces", description, params, returns); +// params.clear(); returns.clear(); +// description = "Get the available UART interfaces in order to set up the zigbee network on the approriate serial interface."; +// returns.insert("uartInterfaces", objectRef()); +// registerMethod("GetUartInterfaces", description, params, returns); // GetNetworkStatus // NetworkStatusChanged @@ -125,11 +125,11 @@ JsonReply *ZigbeeHandler::GetUartInterfaces(const QVariantMap ¶ms) { Q_UNUSED(params) QVariantMap ret; - QVariantList portList; - foreach (const ZigbeeSerialPort &serialPort, m_zigbeeManager->availablePorts()) { - portList << pack(serialPort); - } - ret.insert("uartInterfaces", portList); +// QVariantList portList; +// foreach (const ZigbeeSerialPort &serialPort, m_zigbeeManager->availablePorts()) { +// portList << pack(serialPort); +// } +// ret.insert("uartInterfaces", portList); return createReply(ret); } diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index b940c5dc..430a50fe 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -130,8 +130,7 @@ HEADERS += nymeacore.h \ cloud/cloudtransport.h \ debugreportgenerator.h \ platform/platform.h \ \ - zigbee/zigbeemanager.h \ - zigbee/zigbeeserialport.h + zigbee/zigbeemanager.h SOURCES += nymeacore.cpp \ @@ -217,8 +216,7 @@ SOURCES += nymeacore.cpp \ cloud/cloudtransport.cpp \ debugreportgenerator.cpp \ platform/platform.cpp \ - zigbee/zigbeemanager.cpp \ - zigbee/zigbeeserialport.cpp + zigbee/zigbeemanager.cpp versionAtLeast(QT_VERSION, 5.12.0) { diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 701b8a7e..ce5d98f5 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -56,34 +56,7 @@ ZigbeeNetwork *ZigbeeManager::zigbeeNetwork() const return m_zigbeeNetwork; } -ZigbeeSerialPortList ZigbeeManager::availablePorts() -{ - ZigbeeSerialPortList ports; - foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { - qCDebug(dcZigbee()) << "Found serial port" << serialPortInfo.portName(); - qCDebug(dcZigbee()) << " Description:" << serialPortInfo.description(); - qCDebug(dcZigbee()) << " System location:" << serialPortInfo.systemLocation(); - qCDebug(dcZigbee()) << " Manufacturer:" << serialPortInfo.manufacturer(); - qCDebug(dcZigbee()) << " Serialnumber:" << serialPortInfo.serialNumber(); - - if (serialPortInfo.hasProductIdentifier()) { - qCDebug(dcZigbee()) << " Product identifier:" << serialPortInfo.productIdentifier(); - } - if (serialPortInfo.hasVendorIdentifier()) { - qCDebug(dcZigbee()) << " Vendor identifier:" << serialPortInfo.vendorIdentifier(); - } - - ZigbeeSerialPort port; - port.setName(serialPortInfo.portName()); - port.setDescription(serialPortInfo.description()); - port.setSystemLocation(serialPortInfo.systemLocation()); - ports.append(port); - } - - return ports; -} - -void ZigbeeManager::createZigbeeNetwork(const QString &serialPort, qint32 baudrate, ZigbeeNetworkManager::BackendType backend) +void ZigbeeManager::createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::BackendType backend) { if (m_zigbeeNetwork) { delete m_zigbeeNetwork; diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index 54a4a652..dced5f3f 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -35,8 +35,6 @@ #include -#include "zigbeeserialport.h" - namespace nymeaserver { class ZigbeeManager : public QObject @@ -50,9 +48,7 @@ public: ZigbeeNetwork *zigbeeNetwork() const; - ZigbeeSerialPortList availablePorts(); - - void createZigbeeNetwork(const QString &serialPort, qint32 baudrate, ZigbeeNetworkManager::BackendType backend); + void createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::BackendType backend); private: ZigbeeNetwork *m_zigbeeNetwork = nullptr; diff --git a/libnymea-core/zigbee/zigbeeserialport.cpp b/libnymea-core/zigbee/zigbeeserialport.cpp deleted file mode 100644 index 6b2b12d7..00000000 --- a/libnymea-core/zigbee/zigbeeserialport.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* 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 . -* -* 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 "zigbeeserialport.h" - -namespace nymeaserver { - -ZigbeeSerialPort::ZigbeeSerialPort() -{ - -} - -QString ZigbeeSerialPort::name() const -{ - return m_name; -} - -void ZigbeeSerialPort::setName(const QString &name) -{ - m_name = name; -} - -QString ZigbeeSerialPort::description() const -{ - return m_description; -} - -void ZigbeeSerialPort::setDescription(const QString &description) -{ - m_description = description; -} - -QString ZigbeeSerialPort::systemLocation() const -{ - return m_systemLocation; -} - -void ZigbeeSerialPort::setSystemLocation(const QString &systemLocation) -{ - m_systemLocation = systemLocation; -} - -QVariant ZigbeeSerialPortList::get(int index) const -{ - return QVariant::fromValue(at(index)); -} - -void ZigbeeSerialPortList::put(const QVariant &variant) -{ - append(variant.value()); -} - -} diff --git a/libnymea-core/zigbee/zigbeeserialport.h b/libnymea-core/zigbee/zigbeeserialport.h deleted file mode 100644 index 34397bec..00000000 --- a/libnymea-core/zigbee/zigbeeserialport.h +++ /dev/null @@ -1,77 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* 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 . -* -* 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 ZIGBEESERIALPORT_H -#define ZIGBEESERIALPORT_H - -#include -#include -namespace nymeaserver { - -class ZigbeeSerialPort -{ - Q_GADGET - Q_PROPERTY(QString name READ name) - Q_PROPERTY(QString description READ description) - Q_PROPERTY(QString systemLocation READ systemLocation) - -public: - ZigbeeSerialPort(); - - QString name() const; - void setName(const QString &name); - - QString description() const; - void setDescription(const QString &description); - - QString systemLocation() const; - void setSystemLocation(const QString &systemLocation); - -private: - QString m_name; - QString m_description; - QString m_systemLocation; -}; - -class ZigbeeSerialPortList: public QList -{ - Q_GADGET - Q_PROPERTY(int count READ count) -public: - Q_INVOKABLE QVariant get(int index) const; - Q_INVOKABLE void put(const QVariant &variant); -}; - -} - -Q_DECLARE_METATYPE(nymeaserver::ZigbeeSerialPort) -Q_DECLARE_METATYPE(nymeaserver::ZigbeeSerialPortList) - -#endif // ZIGBEESERIALPORT_H diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp index 45906af3..303e60a2 100644 --- a/libnymea/loggingcategories.cpp +++ b/libnymea/loggingcategories.cpp @@ -76,6 +76,7 @@ NYMEA_LOGGING_CATEGORY(dcBluetoothServerTraffic, "BluetoothServerTraffic") NYMEA_LOGGING_CATEGORY(dcMqtt, "Mqtt") NYMEA_LOGGING_CATEGORY(dcTranslations, "Translations") NYMEA_LOGGING_CATEGORY(dcI2C, "I2C") +NYMEA_LOGGING_CATEGORY(dcZigbeeHardwareResource, "ZigbeeHardwareResource") static QFile s_logFile; From 915cd25a7d9a9e9d626c5a61e9d2e300af1b02a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 28 Oct 2020 09:55:37 +0100 Subject: [PATCH 06/54] Update zigbee resource logging category --- .../zigbeehardwareresourceimplementation.cpp | 16 ++++++++-------- libnymea/loggingcategories.cpp | 3 ++- libnymea/loggingcategories.h | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index edf1172b..a893897b 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -69,12 +69,12 @@ void ZigbeeHardwareResourceImplementation::setZigbeeNetwork(ZigbeeNetwork *netwo void ZigbeeHardwareResourceImplementation::setEnabled(bool enabled) { - qCDebug(dcZigbeeHardwareResource()) << "Set" << (enabled ? "enabled" : "disabled"); + qCDebug(dcZigbeeResource()) << "Set" << (enabled ? "enabled" : "disabled"); if (m_enabled && enabled) { - qCDebug(dcZigbeeHardwareResource()) << "Already enabled."; + qCDebug(dcZigbeeResource()) << "Already enabled."; return; } else if (!m_enabled && !enabled) { - qCDebug(dcZigbeeHardwareResource()) << "Already disabled."; + qCDebug(dcZigbeeResource()) << "Already disabled."; return; } @@ -93,15 +93,15 @@ void ZigbeeHardwareResourceImplementation::setEnabled(bool enabled) void ZigbeeHardwareResourceImplementation::onZigbeeNetworkStateChanged(ZigbeeNetwork::State state) { - qCDebug(dcZigbeeHardwareResource()) << "Network state changed" << state; + qCDebug(dcZigbeeResource()) << "Network state changed" << state; } bool ZigbeeHardwareResourceImplementation::enable() { - qCDebug(dcZigbeeHardwareResource()) << "Enable hardware resource"; + qCDebug(dcZigbeeResource()) << "Enable hardware resource"; if (!m_zigbeeNetwork) { - qCDebug(dcZigbeeHardwareResource()) << "There is no zigbee network configured as hardware resource"; + qCDebug(dcZigbeeResource()) << "There is no zigbee network configured as hardware resource"; } else { // TODO: start network } @@ -111,9 +111,9 @@ bool ZigbeeHardwareResourceImplementation::enable() bool ZigbeeHardwareResourceImplementation::disable() { - qCDebug(dcZigbeeHardwareResource()) << "Disable hardware resource"; + qCDebug(dcZigbeeResource()) << "Disable hardware resource"; if (!m_zigbeeNetwork) { - qCDebug(dcZigbeeHardwareResource()) << "There is no zigbee network configured as hardware resource"; + qCDebug(dcZigbeeResource()) << "There is no zigbee network configured as hardware resource"; } // TODO: stop network diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp index 303e60a2..c40c2141 100644 --- a/libnymea/loggingcategories.cpp +++ b/libnymea/loggingcategories.cpp @@ -76,7 +76,8 @@ NYMEA_LOGGING_CATEGORY(dcBluetoothServerTraffic, "BluetoothServerTraffic") NYMEA_LOGGING_CATEGORY(dcMqtt, "Mqtt") NYMEA_LOGGING_CATEGORY(dcTranslations, "Translations") NYMEA_LOGGING_CATEGORY(dcI2C, "I2C") -NYMEA_LOGGING_CATEGORY(dcZigbeeHardwareResource, "ZigbeeHardwareResource") +NYMEA_LOGGING_CATEGORY(dcZigbee, "Zigbee") +NYMEA_LOGGING_CATEGORY(dcZigbeeResource, "ZigbeeResource") static QFile s_logFile; diff --git a/libnymea/loggingcategories.h b/libnymea/loggingcategories.h index 979173fb..ec0d5251 100644 --- a/libnymea/loggingcategories.h +++ b/libnymea/loggingcategories.h @@ -92,7 +92,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcI2C) Q_DECLARE_LOGGING_CATEGORY(dcIntegrations) Q_DECLARE_LOGGING_CATEGORY(dcJsIntegrations) Q_DECLARE_LOGGING_CATEGORY(dcZigbee) -Q_DECLARE_LOGGING_CATEGORY(dcZigbeeHardwareResource) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeResource) /* From 6e72689c561ea2128c0f547ecbe88f31ba1d122e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 28 Oct 2020 10:26:43 +0100 Subject: [PATCH 07/54] Make use of nymea logging categories and offer libnymea-zigbee ZigbeeNetwork logging category within nymea to enable --- .../zigbee/zigbeehardwareresourceimplementation.cpp | 2 ++ libnymea-core/zigbee/zigbeemanager.cpp | 6 +++++- libnymea/loggingcategories.cpp | 3 --- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index a893897b..f459a4f2 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -37,6 +37,8 @@ #include +NYMEA_LOGGING_CATEGORY(dcZigbeeResource, "ZigbeeResource") + namespace nymeaserver { ZigbeeHardwareResourceImplementation::ZigbeeHardwareResourceImplementation(QObject *parent) : diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index ce5d98f5..af26f5ce 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -32,7 +32,11 @@ #include "nymeasettings.h" #include "loggingcategories.h" -#include +NYMEA_LOGGING_CATEGORY(dcZigbee, "Zigbee") + +// Register debug category from the libnymea-zigbee. +// Do not use this category within nymea! +NYMEA_LOGGING_CATEGORY(dcZigbeeNetwork, "ZigbeeNetwork") namespace nymeaserver { diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp index c40c2141..987b00e2 100644 --- a/libnymea/loggingcategories.cpp +++ b/libnymea/loggingcategories.cpp @@ -76,9 +76,6 @@ NYMEA_LOGGING_CATEGORY(dcBluetoothServerTraffic, "BluetoothServerTraffic") NYMEA_LOGGING_CATEGORY(dcMqtt, "Mqtt") NYMEA_LOGGING_CATEGORY(dcTranslations, "Translations") NYMEA_LOGGING_CATEGORY(dcI2C, "I2C") -NYMEA_LOGGING_CATEGORY(dcZigbee, "Zigbee") -NYMEA_LOGGING_CATEGORY(dcZigbeeResource, "ZigbeeResource") - static QFile s_logFile; static bool s_useColors; From afc97fd244cc706520206148a86ed5a1e31e9cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 28 Oct 2020 10:35:17 +0100 Subject: [PATCH 08/54] Renabe libnymea-zigbee debug category for better understanding from where this category comes from --- libnymea-core/zigbee/zigbeemanager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index af26f5ce..1900c057 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -34,9 +34,8 @@ NYMEA_LOGGING_CATEGORY(dcZigbee, "Zigbee") -// Register debug category from the libnymea-zigbee. -// Do not use this category within nymea! -NYMEA_LOGGING_CATEGORY(dcZigbeeNetwork, "ZigbeeNetwork") +// Register debug category from the libnymea-zigbee +NYMEA_LOGGING_CATEGORY(dcZigbeeNetworkLibNymeaZigbee, "ZigbeeNetwork") namespace nymeaserver { From 4a520d8ba19a142eaf32b9da4be3171d9ceaaf09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 28 Oct 2020 11:42:06 +0100 Subject: [PATCH 09/54] Rename Backend type and define ZigbeeNetworkState within the manager --- libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp | 2 ++ libnymea-core/jsonrpc/zigbeehandler.cpp | 11 ++++------- libnymea-core/zigbee/zigbeemanager.cpp | 2 +- libnymea-core/zigbee/zigbeemanager.h | 10 +++++++++- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp index 33671c20..b613f9ab 100644 --- a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp @@ -73,6 +73,7 @@ #include "tagshandler.h" #include "systemhandler.h" #include "usershandler.h" +#include "zigbeehandler.h" #include #include @@ -595,6 +596,7 @@ void JsonRPCServerImplementation::setup() registerHandler(new TagsHandler(this)); registerHandler(new SystemHandler(NymeaCore::instance()->platform(), this)); registerHandler(new UsersHandler(NymeaCore::instance()->userManager(), this)); + registerHandler(new ZigbeeHandler(NymeaCore::instance()->zigbeeManager(), this)); connect(NymeaCore::instance()->cloudManager(), &CloudManager::pairingReply, this, &JsonRPCServerImplementation::pairingFinished); connect(NymeaCore::instance()->cloudManager(), &CloudManager::connectionStateChanged, this, &JsonRPCServerImplementation::onCloudConnectionStateChanged); diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 8a6ab354..9f4091ef 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -37,11 +37,8 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : JsonHandler(parent), m_zigbeeManager(zigbeeManager) { - registerEnum(); - registerEnum(); - -// registerObject(); -// registerObject(); + registerEnum(); + registerEnum(); QVariantMap params, returns; QString description; @@ -60,13 +57,13 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : returns.insert("configured", enumValueName(Bool)); returns.insert("serialPort", enumValueName(String)); returns.insert("baudRate", enumValueName(Uint)); - returns.insert("backend", enumRef()); + returns.insert("backend", enumRef()); returns.insert("firmwareVersion", enumValueName(String)); returns.insert("networkIeeeeAddress", enumValueName(String)); returns.insert("networkPanId", enumValueName(Uint)); returns.insert("channel", enumValueName(Uint)); returns.insert("permitJoin", enumValueName(Bool)); - returns.insert("networkState", enumRef()); + returns.insert("networkState", enumRef()); registerMethod("GetNetworkStatus", description, params, returns); // GetUartInterfaces diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 1900c057..645d4bae 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -59,7 +59,7 @@ ZigbeeNetwork *ZigbeeManager::zigbeeNetwork() const return m_zigbeeNetwork; } -void ZigbeeManager::createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::BackendType backend) +void ZigbeeManager::createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::ZigbeeBackendType backend) { if (m_zigbeeNetwork) { delete m_zigbeeNetwork; diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index dced5f3f..0ca56680 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -41,6 +41,14 @@ class ZigbeeManager : public QObject { Q_OBJECT public: + enum ZigbeeNetworkState { + ZigbeeNetworkStateOffline, + ZigbeeNetworkStateUpdating, + ZigbeeNetworkStateOnline, + ZigbeeNetworkStateError + }; + Q_ENUM(ZigbeeNetworkState) + explicit ZigbeeManager(QObject *parent = nullptr); bool available() const; @@ -48,7 +56,7 @@ public: ZigbeeNetwork *zigbeeNetwork() const; - void createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::BackendType backend); + void createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::ZigbeeBackendType backend); private: ZigbeeNetwork *m_zigbeeNetwork = nullptr; From 61d0b96b42c901b404668e7361157500ba7c2776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 28 Oct 2020 12:43:56 +0100 Subject: [PATCH 10/54] Add GetAvailableAdapters to zigbee handler --- libnymea-core/jsonrpc/zigbeehandler.cpp | 31 ++++++++------ libnymea-core/jsonrpc/zigbeehandler.h | 2 +- libnymea-core/libnymea-core.pro | 2 + libnymea-core/zigbee/zigbeeadapters.cpp | 56 +++++++++++++++++++++++++ libnymea-core/zigbee/zigbeeadapters.h | 55 ++++++++++++++++++++++++ libnymea-core/zigbee/zigbeemanager.cpp | 5 +++ libnymea-core/zigbee/zigbeemanager.h | 3 ++ 7 files changed, 140 insertions(+), 14 deletions(-) create mode 100644 libnymea-core/zigbee/zigbeeadapters.cpp create mode 100644 libnymea-core/zigbee/zigbeeadapters.h diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 9f4091ef..61976a74 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -30,6 +30,9 @@ #include "zigbeehandler.h" #include "zigbee/zigbeemanager.h" +#include "zigbee/zigbeeadapters.h" + +#include namespace nymeaserver { @@ -40,12 +43,14 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : registerEnum(); registerEnum(); + registerObject(); + QVariantMap params, returns; QString description; /* 1. GetNetworkStatus * 2. Setup network if the is no network configured - * - GetUartInterfaces + * - GetAvailableAdapters * - Setup network with given UART interface and backend type * - */ @@ -66,11 +71,11 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : returns.insert("networkState", enumRef()); registerMethod("GetNetworkStatus", description, params, returns); - // GetUartInterfaces -// params.clear(); returns.clear(); -// description = "Get the available UART interfaces in order to set up the zigbee network on the approriate serial interface."; -// returns.insert("uartInterfaces", objectRef()); -// registerMethod("GetUartInterfaces", description, params, returns); + // GetAvailableAdapters + params.clear(); returns.clear(); + description = "Get the available ZigBee adapters in order to set up the zigbee network on the approriate serial interface. If the adapter has been recognized correctly, the \"backendSuggestionAvailable\" will be true and the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; + returns.insert("zigbeeAdapters", objectRef()); + registerMethod("GetAvailableAdapters", description, params, returns); // GetNetworkStatus // NetworkStatusChanged @@ -118,15 +123,15 @@ JsonReply *ZigbeeHandler::GetNetworkStatus(const QVariantMap ¶ms) return createReply(ret); } -JsonReply *ZigbeeHandler::GetUartInterfaces(const QVariantMap ¶ms) +JsonReply *ZigbeeHandler::GetAvailableAdapters(const QVariantMap ¶ms) { Q_UNUSED(params) - QVariantMap ret; -// QVariantList portList; -// foreach (const ZigbeeSerialPort &serialPort, m_zigbeeManager->availablePorts()) { -// portList << pack(serialPort); -// } -// ret.insert("uartInterfaces", portList); + + QVariantMap ret; QVariantList adapterList; + foreach (const ZigbeeAdapter &adapter, m_zigbeeManager->availableAdapters()) { + adapterList << pack(adapter); + } + ret.insert("zigbeeAdapters", adapterList); return createReply(ret); } diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h index 376eb24f..c94c9d07 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.h +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -50,7 +50,7 @@ public: QString name() const override; Q_INVOKABLE JsonReply *GetNetworkStatus(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply *GetUartInterfaces(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetAvailableAdapters(const QVariantMap ¶ms); private: diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 430a50fe..52370808 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -130,6 +130,7 @@ HEADERS += nymeacore.h \ cloud/cloudtransport.h \ debugreportgenerator.h \ platform/platform.h \ \ + zigbee/zigbeeadapters.h \ zigbee/zigbeemanager.h @@ -216,6 +217,7 @@ SOURCES += nymeacore.cpp \ cloud/cloudtransport.cpp \ debugreportgenerator.cpp \ platform/platform.cpp \ + zigbee/zigbeeadapters.cpp \ zigbee/zigbeemanager.cpp diff --git a/libnymea-core/zigbee/zigbeeadapters.cpp b/libnymea-core/zigbee/zigbeeadapters.cpp new file mode 100644 index 00000000..7379fd2a --- /dev/null +++ b/libnymea-core/zigbee/zigbeeadapters.cpp @@ -0,0 +1,56 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 "zigbeeadapters.h" + +namespace nymeaserver { + +ZigbeeAdapters::ZigbeeAdapters() +{ + +} + +ZigbeeAdapters::ZigbeeAdapters(const QList &other) : + QList(other) +{ + +} + +QVariant ZigbeeAdapters::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void ZigbeeAdapters::put(const QVariant &variant) +{ + append(variant.value()); +} + +} diff --git a/libnymea-core/zigbee/zigbeeadapters.h b/libnymea-core/zigbee/zigbeeadapters.h new file mode 100644 index 00000000..7d400f33 --- /dev/null +++ b/libnymea-core/zigbee/zigbeeadapters.h @@ -0,0 +1,55 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 ZIGBEEADAPTERS_H +#define ZIGBEEADAPTERS_H + +#include +#include + +namespace nymeaserver { + +class ZigbeeAdapters : public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) + +public: + ZigbeeAdapters(); + ZigbeeAdapters(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; + +} + +Q_DECLARE_METATYPE(nymeaserver::ZigbeeAdapters) + +#endif // ZIGBEEADAPTERS_H diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 645d4bae..568a9d2e 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -59,6 +59,11 @@ ZigbeeNetwork *ZigbeeManager::zigbeeNetwork() const return m_zigbeeNetwork; } +ZigbeeAdapters ZigbeeManager::availableAdapters() +{ + return ZigbeeNetworkManager::availableAdapters(); +} + void ZigbeeManager::createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::ZigbeeBackendType backend) { if (m_zigbeeNetwork) { diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index 0ca56680..45dd5f9c 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -35,6 +35,8 @@ #include +#include "zigbeeadapters.h" + namespace nymeaserver { class ZigbeeManager : public QObject @@ -55,6 +57,7 @@ public: bool enabled() const; ZigbeeNetwork *zigbeeNetwork() const; + ZigbeeAdapters availableAdapters(); void createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::ZigbeeBackendType backend); From 19216b5f044c8a01961787fea9b2556d710e67e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 28 Oct 2020 16:52:42 +0100 Subject: [PATCH 11/54] Add Zigbee settings and prepare network creation and loading --- libnymea-core/jsonrpc/zigbeehandler.cpp | 66 +++++++++---- libnymea-core/jsonrpc/zigbeehandler.h | 5 +- libnymea-core/libnymea-core.pro | 2 + libnymea-core/zigbee/zigbeeadapter.cpp | 124 ++++++++++++++++++++++++ libnymea-core/zigbee/zigbeeadapter.h | 91 +++++++++++++++++ libnymea-core/zigbee/zigbeeadapters.h | 3 +- libnymea-core/zigbee/zigbeemanager.cpp | 47 ++++++++- libnymea-core/zigbee/zigbeemanager.h | 22 +++++ libnymea/nymeasettings.cpp | 3 + libnymea/nymeasettings.h | 1 + 10 files changed, 342 insertions(+), 22 deletions(-) create mode 100644 libnymea-core/zigbee/zigbeeadapter.cpp create mode 100644 libnymea-core/zigbee/zigbeeadapter.h diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 61976a74..6995076c 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -32,7 +32,7 @@ #include "zigbee/zigbeemanager.h" #include "zigbee/zigbeeadapters.h" -#include +#include namespace nymeaserver { @@ -41,19 +41,36 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : m_zigbeeManager(zigbeeManager) { registerEnum(); - registerEnum(); + registerEnum(); + registerEnum(); registerObject(); + // Network object describing a network instance + QVariantMap zigbeeNetworkDescription; + zigbeeNetworkDescription.insert("id", enumValueName(Uuid)); + registerObject("ZigbeeNetwork", zigbeeNetworkDescription); + QVariantMap params, returns; QString description; - /* 1. GetNetworkStatus - * 2. Setup network if the is no network configured - * - GetAvailableAdapters - * - Setup network with given UART interface and backend type - * - - */ + // GetAdapters + params.clear(); returns.clear(); + description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network on the desired serial interface. If an adapter has been recognized correctly as a supported hardware, the backendSuggestionAvailable property will be true and the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; + returns.insert("adapters", objectRef()); + registerMethod("GetAdapters", description, params, returns); + + // AdapterAdded notification + params.clear(); + description = "Emitted whenever a new ZigBee adapter candidate has been detected in the system."; + params.insert("adapter", objectRef()); + registerNotification("AdapterAdded", description, params); + + // AdapterRemoved notification + params.clear(); + description = "Emitted whenever a ZigBee adapter has been removed from the system (i.e. unplugged)."; + params.insert("adapters", objectRef()); + registerNotification("AdapterRemoved", description, params); params.clear(); returns.clear(); description = "Get the status of the current network."; @@ -71,11 +88,25 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : returns.insert("networkState", enumRef()); registerMethod("GetNetworkStatus", description, params, returns); - // GetAvailableAdapters - params.clear(); returns.clear(); - description = "Get the available ZigBee adapters in order to set up the zigbee network on the approriate serial interface. If the adapter has been recognized correctly, the \"backendSuggestionAvailable\" will be true and the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; - returns.insert("zigbeeAdapters", objectRef()); - registerMethod("GetAvailableAdapters", description, params, returns); + connect(m_zigbeeManager, &ZigbeeManager::availableAdapterAdded, this, [this](const ZigbeeAdapter &adapter){ + QVariantMap params; + params.insert("adapter", pack(adapter)); + emit AdapterAdded(params); + }); + + connect(m_zigbeeManager, &ZigbeeManager::availableAdapterRemoved, this, [this](const ZigbeeAdapter &adapter){ + QVariantMap params; + params.insert("adapter", pack(adapter)); + emit AdapterRemoved(params); + }); + + /* 1. GetNetworkStatus + * 2. Setup network if the is no network configured + * - GetAvailableAdapters + * - Setup network with given UART interface and backend type + * - + */ + // GetNetworkStatus // NetworkStatusChanged @@ -123,16 +154,17 @@ JsonReply *ZigbeeHandler::GetNetworkStatus(const QVariantMap ¶ms) return createReply(ret); } -JsonReply *ZigbeeHandler::GetAvailableAdapters(const QVariantMap ¶ms) +JsonReply *ZigbeeHandler::GetAdapters(const QVariantMap ¶ms) { Q_UNUSED(params) - QVariantMap ret; QVariantList adapterList; + QVariantMap returnMap; + QVariantList adapterList; foreach (const ZigbeeAdapter &adapter, m_zigbeeManager->availableAdapters()) { adapterList << pack(adapter); } - ret.insert("zigbeeAdapters", adapterList); - return createReply(ret); + returnMap.insert("adapters", adapterList); + return createReply(returnMap); } } diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h index c94c9d07..3b99035a 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.h +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -50,13 +50,14 @@ public: QString name() const override; Q_INVOKABLE JsonReply *GetNetworkStatus(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply *GetAvailableAdapters(const QVariantMap ¶ms); - + Q_INVOKABLE JsonReply *GetAdapters(const QVariantMap ¶ms); private: ZigbeeManager *m_zigbeeManager = nullptr; signals: + void AdapterAdded(const QVariantMap ¶ms); + void AdapterRemoved(const QVariantMap ¶ms); }; diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 52370808..08365605 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -130,6 +130,7 @@ HEADERS += nymeacore.h \ cloud/cloudtransport.h \ debugreportgenerator.h \ platform/platform.h \ \ + zigbee/zigbeeadapter.h \ zigbee/zigbeeadapters.h \ zigbee/zigbeemanager.h @@ -217,6 +218,7 @@ SOURCES += nymeacore.cpp \ cloud/cloudtransport.cpp \ debugreportgenerator.cpp \ platform/platform.cpp \ + zigbee/zigbeeadapter.cpp \ zigbee/zigbeeadapters.cpp \ zigbee/zigbeemanager.cpp diff --git a/libnymea-core/zigbee/zigbeeadapter.cpp b/libnymea-core/zigbee/zigbeeadapter.cpp new file mode 100644 index 00000000..7c099398 --- /dev/null +++ b/libnymea-core/zigbee/zigbeeadapter.cpp @@ -0,0 +1,124 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 "zigbeeadapter.h" + +namespace nymeaserver { + +ZigbeeAdapter::ZigbeeAdapter() +{ + +} + +QString ZigbeeAdapter::name() const +{ + return m_name; +} + +void ZigbeeAdapter::setName(const QString &name) +{ + m_name = name; +} + +QString ZigbeeAdapter::description() const +{ + return m_description; +} + +void ZigbeeAdapter::setDescription(const QString &description) +{ + m_description = description; +} + +QString ZigbeeAdapter::systemLocation() const +{ + return m_systemLocation; +} + +void ZigbeeAdapter::setSystemLocation(const QString &systemLocation) +{ + m_systemLocation = systemLocation; +} + +bool ZigbeeAdapter::backendSuggestionAvailable() const +{ + return m_backendSuggestionAvailable; +} + +void ZigbeeAdapter::setBackendSuggestionAvailable(bool backendSuggestionAvailable) +{ + m_backendSuggestionAvailable = backendSuggestionAvailable; +} + +Zigbee::ZigbeeBackendType ZigbeeAdapter::suggestedZigbeeBackendType() const +{ + return m_suggestedZigbeeBackendType; +} + +void ZigbeeAdapter::setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendType backendType) +{ + m_suggestedZigbeeBackendType = backendType; +} + +qint32 ZigbeeAdapter::suggestedBaudRate() const +{ + return m_suggestedBaudRate; +} + +void ZigbeeAdapter::setSuggestedBaudRate(qint32 baudRate) +{ + m_suggestedBaudRate = baudRate; +} + +bool ZigbeeAdapter::operator==(const ZigbeeAdapter &other) const +{ + return m_systemLocation == other.systemLocation() + && m_name == other.name() + && m_description == other.description() + && m_backendSuggestionAvailable == other.backendSuggestionAvailable() + && m_suggestedZigbeeBackendType == other.suggestedZigbeeBackendType() + && m_suggestedBaudRate == other.suggestedBaudRate(); +} + + +QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter) +{ + debug.nospace() << "ZigbeeAdapter(" << adapter.name() << " - " << adapter.description(); + debug.nospace() << ", " << adapter.systemLocation(); + if (adapter.backendSuggestionAvailable()) { + debug.nospace() << "Suggested backend: " << adapter.suggestedZigbeeBackendType(); + debug.nospace() << ", " << adapter.suggestedBaudRate(); + } + + debug.nospace() << ")"; + return debug.space(); +} + +} diff --git a/libnymea-core/zigbee/zigbeeadapter.h b/libnymea-core/zigbee/zigbeeadapter.h new file mode 100644 index 00000000..8ffe8618 --- /dev/null +++ b/libnymea-core/zigbee/zigbeeadapter.h @@ -0,0 +1,91 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 ZIGBEEADAPTER_H +#define ZIGBEEADAPTER_H + +#include +#include + +#include "zigbee.h" + +namespace nymeaserver { + +class ZigbeeAdapter +{ + Q_GADGET + Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString description READ description) + Q_PROPERTY(QString systemLocation READ systemLocation) + Q_PROPERTY(bool backendSuggestionAvailable READ backendSuggestionAvailable) + Q_PROPERTY(Zigbee::ZigbeeBackendType suggestedZigbeeBackendType READ suggestedZigbeeBackendType) + Q_PROPERTY(qint32 suggestedBaudRate READ suggestedBaudRate) + +public: + explicit ZigbeeAdapter(); + + QString name() const; + void setName(const QString &name); + + QString description() const; + void setDescription(const QString &description); + + QString systemLocation() const; + void setSystemLocation(const QString &systemLocation); + + bool backendSuggestionAvailable() const; + void setBackendSuggestionAvailable(bool backendSuggestionAvailable); + + Zigbee::ZigbeeBackendType suggestedZigbeeBackendType() const; + void setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendType backendType); + + qint32 suggestedBaudRate() const; + void setSuggestedBaudRate(qint32 baudRate); + + bool operator==(const ZigbeeAdapter &other) const; + +private: + QString m_name; + QString m_description; + QString m_systemLocation; + + bool m_backendSuggestionAvailable = false; + Zigbee::ZigbeeBackendType m_suggestedZigbeeBackendType = Zigbee::ZigbeeBackendTypeDeconz; + qint32 m_suggestedBaudRate = 38400; +}; + +QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter); + +} + +Q_DECLARE_METATYPE(nymeaserver::ZigbeeAdapter) + +#endif // ZIGBEEADAPTER_H + diff --git a/libnymea-core/zigbee/zigbeeadapters.h b/libnymea-core/zigbee/zigbeeadapters.h index 7d400f33..05528e86 100644 --- a/libnymea-core/zigbee/zigbeeadapters.h +++ b/libnymea-core/zigbee/zigbeeadapters.h @@ -32,7 +32,8 @@ #define ZIGBEEADAPTERS_H #include -#include + +#include "zigbeeadapter.h" namespace nymeaserver { diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 568a9d2e..7c635ea3 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -41,7 +41,39 @@ namespace nymeaserver { ZigbeeManager::ZigbeeManager(QObject *parent) : QObject(parent) { + // Adapter monitor + qCDebug(dcZigbee()) << "Initialize the ZigBee manager"; + m_adapterMonitor = new ZigbeeUartAdapterMonitor(this); + if (!m_adapterMonitor->isValid()) { + qCWarning(dcZigbee()) << "Could not initialize the ZigBee adapter monitor."; + // Lets continue anyways, maybe we can set up existing networks right the way. + } + foreach(const ZigbeeUartAdapter &uartAdapter, m_adapterMonitor->availableAdapters()) { + m_adapters.append(createAdapterFromUartAdapter(uartAdapter)); + } + + connect(m_adapterMonitor, &ZigbeeUartAdapterMonitor::adapterAdded, this, [this](const ZigbeeUartAdapter &uartAdapter){ + ZigbeeAdapter adapter = createAdapterFromUartAdapter(uartAdapter); + m_adapters.append(adapter); + emit availableAdapterAdded(adapter); + }); + + connect(m_adapterMonitor, &ZigbeeUartAdapterMonitor::adapterRemoved, this, [this](const ZigbeeUartAdapter &uartAdapter){ + foreach (const ZigbeeAdapter &adapter, m_adapters) { + if (adapter.systemLocation() == uartAdapter.systemLocation()) { + m_adapters.removeAll(adapter); + emit availableAdapterRemoved(adapter); + } + } + }); + + // Load zigbee networks from settings + NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); + + + + // TODO: load platform configuration for networks we know for sure how they work } bool ZigbeeManager::available() const @@ -61,7 +93,7 @@ ZigbeeNetwork *ZigbeeManager::zigbeeNetwork() const ZigbeeAdapters ZigbeeManager::availableAdapters() { - return ZigbeeNetworkManager::availableAdapters(); + return m_adapters; } void ZigbeeManager::createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::ZigbeeBackendType backend) @@ -75,10 +107,21 @@ void ZigbeeManager::createZigbeeNetwork(const QString &serialPort, qint32 baudra m_zigbeeNetwork->setSerialPortName(serialPort); m_zigbeeNetwork->setSerialBaudrate(baudrate); m_zigbeeNetwork->setSettingsFileName(NymeaSettings(NymeaSettings::SettingsRoleGlobal).fileName()); - m_zigbeeNetwork->startNetwork(); emit zigbeeNetworkChanged(m_zigbeeNetwork); } +ZigbeeAdapter ZigbeeManager::createAdapterFromUartAdapter(const ZigbeeUartAdapter &uartAdapter) +{ + ZigbeeAdapter adapter; + adapter.setName(uartAdapter.name()); + adapter.setSystemLocation(uartAdapter.systemLocation()); + adapter.setDescription(uartAdapter.description()); + adapter.setBackendSuggestionAvailable(uartAdapter.backendSuggestionAvailable()); + adapter.setSuggestedZigbeeBackendType(uartAdapter.suggestedZigbeeBackendType()); + adapter.setSuggestedBaudRate(uartAdapter.suggestedBaudRate()); + return adapter; +} + } diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index 45dd5f9c..7ec50dd8 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -34,6 +34,7 @@ #include #include +#include #include "zigbeeadapters.h" @@ -43,6 +44,12 @@ class ZigbeeManager : public QObject { Q_OBJECT public: + enum ZigbeeBackendType { + ZigbeeBackendTypeDconz, + ZigbeeBackendTypeNxp + }; + Q_ENUM(ZigbeeBackendType) + enum ZigbeeNetworkState { ZigbeeNetworkStateOffline, ZigbeeNetworkStateUpdating, @@ -51,6 +58,13 @@ public: }; Q_ENUM(ZigbeeNetworkState) + enum ZigbeeError { + ZigbeeErrorNoError, + ZigbeeErrorAdapterNotAvailable, + ZigbeeErrorAdapterAlreadyInUse + }; + Q_ENUM(ZigbeeError) + explicit ZigbeeManager(QObject *parent = nullptr); bool available() const; @@ -62,9 +76,17 @@ public: void createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::ZigbeeBackendType backend); private: + ZigbeeAdapters m_adapters; + ZigbeeUartAdapterMonitor *m_adapterMonitor = nullptr; + ZigbeeNetwork *m_zigbeeNetwork = nullptr; + ZigbeeAdapter createAdapterFromUartAdapter(const ZigbeeUartAdapter &uartAdapter); + signals: + void availableAdapterAdded(const ZigbeeAdapter &adapter); + void availableAdapterRemoved(const ZigbeeAdapter &adapter); + void zigbeeNetworkChanged(ZigbeeNetwork *zigbeeNetwork); }; diff --git a/libnymea/nymeasettings.cpp b/libnymea/nymeasettings.cpp index f7f2324e..417c7472 100644 --- a/libnymea/nymeasettings.cpp +++ b/libnymea/nymeasettings.cpp @@ -122,6 +122,9 @@ NymeaSettings::NymeaSettings(const SettingsRole &role, QObject *parent): case SettingsRoleIOConnections: fileName = "ioconnections.conf"; break; + case SettingsRoleZigbee: + fileName = "zigbee.conf"; + break; } m_settings = new QSettings(basePath + settingsPrefix + fileName, QSettings::IniFormat, this); } diff --git a/libnymea/nymeasettings.h b/libnymea/nymeasettings.h index 8c810e1d..36301eb3 100644 --- a/libnymea/nymeasettings.h +++ b/libnymea/nymeasettings.h @@ -52,6 +52,7 @@ public: SettingsRoleTags, SettingsRoleMqttPolicies, SettingsRoleIOConnections, + SettingsRoleZigbee, }; explicit NymeaSettings(const SettingsRole &role = SettingsRoleNone, QObject *parent = nullptr); From a7cb0e4e2650a02603df624f8c94190b99af113e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 29 Oct 2020 11:44:53 +0100 Subject: [PATCH 12/54] Add network settings loading and saving --- libnymea-core/jsonrpc/zigbeehandler.cpp | 13 +- libnymea-core/zigbee/zigbeeadapter.cpp | 36 ++-- libnymea-core/zigbee/zigbeeadapter.h | 31 ++-- libnymea-core/zigbee/zigbeemanager.cpp | 210 +++++++++++++++++++++--- libnymea-core/zigbee/zigbeemanager.h | 21 +-- 5 files changed, 237 insertions(+), 74 deletions(-) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 6995076c..ee2f1480 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -41,14 +41,14 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : m_zigbeeManager(zigbeeManager) { registerEnum(); - registerEnum(); + registerEnum(); registerEnum(); registerObject(); // Network object describing a network instance QVariantMap zigbeeNetworkDescription; - zigbeeNetworkDescription.insert("id", enumValueName(Uuid)); + zigbeeNetworkDescription.insert("uuid", enumValueName(Uuid)); registerObject("ZigbeeNetwork", zigbeeNetworkDescription); QVariantMap params, returns; @@ -56,7 +56,7 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // GetAdapters params.clear(); returns.clear(); - description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network on the desired serial interface. If an adapter has been recognized correctly as a supported hardware, the backendSuggestionAvailable property will be true and the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; + description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network on the desired serial interface. If an adapter hardware has been recognized as a supported hardware, the \'hardwareRecognized\' property will be true and the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; returns.insert("adapters", objectRef()); registerMethod("GetAdapters", description, params, returns); @@ -100,14 +100,13 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : emit AdapterRemoved(params); }); - /* 1. GetNetworkStatus + /* 1. GetNetworks * 2. Setup network if the is no network configured - * - GetAvailableAdapters - * - Setup network with given UART interface and backend type + * - GetAdapters + * - AddNetwork (adapter, channelmask) * - */ - // GetNetworkStatus // NetworkStatusChanged // SetupNetwork(network, uart, baudrate, backendtype) diff --git a/libnymea-core/zigbee/zigbeeadapter.cpp b/libnymea-core/zigbee/zigbeeadapter.cpp index 7c099398..ce1af680 100644 --- a/libnymea-core/zigbee/zigbeeadapter.cpp +++ b/libnymea-core/zigbee/zigbeeadapter.cpp @@ -67,34 +67,34 @@ void ZigbeeAdapter::setSystemLocation(const QString &systemLocation) m_systemLocation = systemLocation; } -bool ZigbeeAdapter::backendSuggestionAvailable() const +bool ZigbeeAdapter::hardwareRecognized() const { - return m_backendSuggestionAvailable; + return m_hardwareRecognized; } -void ZigbeeAdapter::setBackendSuggestionAvailable(bool backendSuggestionAvailable) +void ZigbeeAdapter::setHardwareRecognized(bool hardwareRecognized) { - m_backendSuggestionAvailable = backendSuggestionAvailable; + m_hardwareRecognized = hardwareRecognized; } -Zigbee::ZigbeeBackendType ZigbeeAdapter::suggestedZigbeeBackendType() const +ZigbeeAdapter::ZigbeeBackendType ZigbeeAdapter::backendType() const { - return m_suggestedZigbeeBackendType; + return m_backendType; } -void ZigbeeAdapter::setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendType backendType) +void ZigbeeAdapter::setBackendType(ZigbeeAdapter::ZigbeeBackendType backendType) { - m_suggestedZigbeeBackendType = backendType; + m_backendType = backendType; } -qint32 ZigbeeAdapter::suggestedBaudRate() const +qint32 ZigbeeAdapter::baudRate() const { - return m_suggestedBaudRate; + return m_baudRate; } -void ZigbeeAdapter::setSuggestedBaudRate(qint32 baudRate) +void ZigbeeAdapter::setBaudRate(qint32 baudRate) { - m_suggestedBaudRate = baudRate; + m_baudRate = baudRate; } bool ZigbeeAdapter::operator==(const ZigbeeAdapter &other) const @@ -102,9 +102,9 @@ bool ZigbeeAdapter::operator==(const ZigbeeAdapter &other) const return m_systemLocation == other.systemLocation() && m_name == other.name() && m_description == other.description() - && m_backendSuggestionAvailable == other.backendSuggestionAvailable() - && m_suggestedZigbeeBackendType == other.suggestedZigbeeBackendType() - && m_suggestedBaudRate == other.suggestedBaudRate(); + && m_hardwareRecognized == other.hardwareRecognized() + && m_backendType == other.backendType() + && m_baudRate == other.baudRate(); } @@ -112,9 +112,9 @@ QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter) { debug.nospace() << "ZigbeeAdapter(" << adapter.name() << " - " << adapter.description(); debug.nospace() << ", " << adapter.systemLocation(); - if (adapter.backendSuggestionAvailable()) { - debug.nospace() << "Suggested backend: " << adapter.suggestedZigbeeBackendType(); - debug.nospace() << ", " << adapter.suggestedBaudRate(); + if (adapter.hardwareRecognized()) { + debug.nospace() << "Hardware recognized: " << adapter.backendType(); + debug.nospace() << ", " << adapter.baudRate(); } debug.nospace() << ")"; diff --git a/libnymea-core/zigbee/zigbeeadapter.h b/libnymea-core/zigbee/zigbeeadapter.h index 8ffe8618..08f88c18 100644 --- a/libnymea-core/zigbee/zigbeeadapter.h +++ b/libnymea-core/zigbee/zigbeeadapter.h @@ -44,11 +44,17 @@ class ZigbeeAdapter Q_PROPERTY(QString name READ name) Q_PROPERTY(QString description READ description) Q_PROPERTY(QString systemLocation READ systemLocation) - Q_PROPERTY(bool backendSuggestionAvailable READ backendSuggestionAvailable) - Q_PROPERTY(Zigbee::ZigbeeBackendType suggestedZigbeeBackendType READ suggestedZigbeeBackendType) - Q_PROPERTY(qint32 suggestedBaudRate READ suggestedBaudRate) + Q_PROPERTY(bool hardwareRecognized READ hardwareRecognized) + Q_PROPERTY(ZigbeeAdapter::ZigbeeBackendType backendType READ backendType) + Q_PROPERTY(qint32 baudRate READ baudRate) public: + enum ZigbeeBackendType { + ZigbeeBackendTypeDeconz, + ZigbeeBackendTypeNxp + }; + Q_ENUM(ZigbeeBackendType) + explicit ZigbeeAdapter(); QString name() const; @@ -60,14 +66,14 @@ public: QString systemLocation() const; void setSystemLocation(const QString &systemLocation); - bool backendSuggestionAvailable() const; - void setBackendSuggestionAvailable(bool backendSuggestionAvailable); + bool hardwareRecognized() const; + void setHardwareRecognized(bool hardwareRecognized); - Zigbee::ZigbeeBackendType suggestedZigbeeBackendType() const; - void setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendType backendType); + ZigbeeAdapter::ZigbeeBackendType backendType() const; + void setBackendType(ZigbeeAdapter::ZigbeeBackendType backendType); - qint32 suggestedBaudRate() const; - void setSuggestedBaudRate(qint32 baudRate); + qint32 baudRate() const; + void setBaudRate(qint32 baudRate); bool operator==(const ZigbeeAdapter &other) const; @@ -75,10 +81,9 @@ private: QString m_name; QString m_description; QString m_systemLocation; - - bool m_backendSuggestionAvailable = false; - Zigbee::ZigbeeBackendType m_suggestedZigbeeBackendType = Zigbee::ZigbeeBackendTypeDeconz; - qint32 m_suggestedBaudRate = 38400; + bool m_hardwareRecognized = false; + ZigbeeAdapter::ZigbeeBackendType m_backendType = ZigbeeAdapter::ZigbeeBackendTypeDeconz; + qint32 m_baudRate = 38400; }; QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter); diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 7c635ea3..c3c29081 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -39,7 +39,8 @@ NYMEA_LOGGING_CATEGORY(dcZigbeeNetworkLibNymeaZigbee, "ZigbeeNetwork") namespace nymeaserver { -ZigbeeManager::ZigbeeManager(QObject *parent) : QObject(parent) +ZigbeeManager::ZigbeeManager(QObject *parent) : + QObject(parent) { // Adapter monitor qCDebug(dcZigbee()) << "Initialize the ZigBee manager"; @@ -49,12 +50,16 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : QObject(parent) // Lets continue anyways, maybe we can set up existing networks right the way. } + qCDebug(dcZigbee()) << "Loading initial adapter list"; foreach(const ZigbeeUartAdapter &uartAdapter, m_adapterMonitor->availableAdapters()) { - m_adapters.append(createAdapterFromUartAdapter(uartAdapter)); + ZigbeeAdapter adapter = createAdapterFromUartAdapter(uartAdapter); + qCDebug(dcZigbee()) << "Adapter added" << adapter; + m_adapters.append(adapter); } connect(m_adapterMonitor, &ZigbeeUartAdapterMonitor::adapterAdded, this, [this](const ZigbeeUartAdapter &uartAdapter){ ZigbeeAdapter adapter = createAdapterFromUartAdapter(uartAdapter); + qCDebug(dcZigbee()) << "Adapter added" << adapter; m_adapters.append(adapter); emit availableAdapterAdded(adapter); }); @@ -62,6 +67,7 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : QObject(parent) connect(m_adapterMonitor, &ZigbeeUartAdapterMonitor::adapterRemoved, this, [this](const ZigbeeUartAdapter &uartAdapter){ foreach (const ZigbeeAdapter &adapter, m_adapters) { if (adapter.systemLocation() == uartAdapter.systemLocation()) { + qCDebug(dcZigbee()) << "Adapter removed" << adapter; m_adapters.removeAll(adapter); emit availableAdapterRemoved(adapter); } @@ -69,47 +75,189 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : QObject(parent) }); // Load zigbee networks from settings - NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); - - + loadZigbeeNetworks(); // TODO: load platform configuration for networks we know for sure how they work } bool ZigbeeManager::available() const { - return m_zigbeeNetwork != nullptr; + return !m_zigbeeNetworks.isEmpty(); } bool ZigbeeManager::enabled() const { - return m_zigbeeNetwork && m_zigbeeNetwork->state() != ZigbeeNetwork::StateUninitialized; + return true;//m_zigbeeNetwork && m_zigbeeNetwork->state() != ZigbeeNetwork::StateUninitialized; } -ZigbeeNetwork *ZigbeeManager::zigbeeNetwork() const -{ - return m_zigbeeNetwork; -} - -ZigbeeAdapters ZigbeeManager::availableAdapters() +ZigbeeAdapters ZigbeeManager::availableAdapters() const { return m_adapters; } -void ZigbeeManager::createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::ZigbeeBackendType backend) +ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask) { - if (m_zigbeeNetwork) { - delete m_zigbeeNetwork; - m_zigbeeNetwork = nullptr; + qCDebug(dcZigbee()) << "Start creating network for" << adapter << channelMask; + + // Make sure we don't have aleardy a network for this adapter + foreach (ZigbeeNetwork *existingNetwork, m_zigbeeNetworks.values()) { + if (existingNetwork->serialPortName() == adapter.systemLocation()) { + qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "which is already in use for network" << existingNetwork->networkUuid().toString(); + return ZigbeeManager::ZigbeeErrorAdapterAlreadyInUse; + } } - m_zigbeeNetwork = ZigbeeNetworkManager::createZigbeeNetwork(backend, this); - m_zigbeeNetwork->setSerialPortName(serialPort); - m_zigbeeNetwork->setSerialBaudrate(baudrate); - m_zigbeeNetwork->setSettingsFileName(NymeaSettings(NymeaSettings::SettingsRoleGlobal).fileName()); - m_zigbeeNetwork->startNetwork(); + if (!m_adapters.contains(adapter)) { + qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "because the adapter is not available any more"; + return ZigbeeManager::ZigbeeErrorAdapterNotAvailable; + } - emit zigbeeNetworkChanged(m_zigbeeNetwork); + ZigbeeNetwork *network = buildNetworkObject(QUuid::createUuid(), adapter.backendType()); + network->setChannelMask(channelMask); + network->setSerialPortName(adapter.systemLocation()); + network->setSerialBaudrate(adapter.baudRate()); + addNetwork(network); + + qCDebug(dcZigbee()) << "Starting zigbee network" << network->networkUuid().toString(); + network->startNetwork(); + + return ZigbeeErrorNoError; +} + +void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) +{ + NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); + settings.beginGroup("ZigbeeNetworks"); + settings.beginGroup(network->networkUuid().toString()); + settings.setValue("serialPort", network->serialPortName()); + settings.setValue("baudRate", network->serialBaudrate()); + switch (network->backendType()) { + case Zigbee::ZigbeeBackendTypeDeconz: + settings.setValue("backendType", static_cast(ZigbeeAdapter::ZigbeeBackendTypeDeconz)); + break; + case Zigbee::ZigbeeBackendTypeNxp: + settings.setValue("backendType", static_cast(ZigbeeAdapter::ZigbeeBackendTypeNxp)); + break; + default: + qCWarning(dcZigbee()) << "Unhandled backend type" << network->backendType() << "which is not implemented in nymea yet."; + break; + } + settings.setValue("panId", network->panId()); + settings.setValue("channel", network->channel()); + + settings.setValue("channelMask", network->channelMask().toUInt32()); + settings.setValue("networkKey", network->securityConfiguration().networkKey().toString()); + settings.setValue("trustCenterLinkKey", network->securityConfiguration().globalTrustCenterLinkKey().toString()); + + settings.endGroup(); // networkUuid + settings.endGroup(); // ZigbeeNetworks +} + +void ZigbeeManager::loadZigbeeNetworks() +{ + NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); + settings.beginGroup("ZigbeeNetworks"); + + foreach (const QString networkUuidGroupString, settings.childGroups()) { + settings.beginGroup(networkUuidGroupString); + + QUuid networkUuid = QUuid(networkUuidGroupString); + QString serialPortName = settings.value("serialPort").toString(); + qint32 serialBaudRate = settings.value("baudRate").toInt(); + ZigbeeAdapter::ZigbeeBackendType backendType = static_cast(settings.value("backendType").toInt()); + quint16 panId = static_cast(settings.value("panId", 0).toUInt()); + quint8 channel = settings.value("channel", 0).toUInt(); + ZigbeeChannelMask channelMask = ZigbeeChannelMask(static_cast(settings.value("channelMask").toUInt())); + + ZigbeeSecurityConfiguration securityConfiguration; + ZigbeeNetworkKey netKey(settings.value("networkKey", QString()).toString()); + if (netKey.isValid()) { + securityConfiguration.setNetworkKey(netKey); + } + + ZigbeeNetworkKey tcKey(settings.value("trustCenterLinkKey", QString("5A6967426565416C6C69616E63653039")).toString()); + if (!tcKey.isValid()) { + securityConfiguration.setGlobalTrustCenterlinkKey(tcKey); + } + + ZigbeeNetwork *network = buildNetworkObject(networkUuid, backendType); + network->setSerialPortName(serialPortName); + network->setSerialBaudrate(serialBaudRate); + network->setPanId(panId); + network->setChannel(channel); + network->setChannelMask(channelMask); + network->setSecurityConfiguration(securityConfiguration); + addNetwork(network); + settings.endGroup(); // networkUuid + } + settings.endGroup(); // ZigbeeNetworks + + if (m_zigbeeNetworks.isEmpty()) { + qCDebug(dcZigbee()) << "There are no zigbee networks configured yet."; + } + + // Start all loaded networks + foreach (ZigbeeNetwork *network, m_zigbeeNetworks.values()) { + network->startNetwork(); + } +} + +ZigbeeNetwork *ZigbeeManager::buildNetworkObject(const QUuid &networkId, ZigbeeAdapter::ZigbeeBackendType backendType) +{ + ZigbeeNetwork *network = nullptr; + switch (backendType) { + case ZigbeeAdapter::ZigbeeBackendTypeDeconz: + network = ZigbeeNetworkManager::createZigbeeNetwork(networkId, Zigbee::ZigbeeBackendTypeDeconz, this); + break; + case ZigbeeAdapter::ZigbeeBackendTypeNxp: + network = ZigbeeNetworkManager::createZigbeeNetwork(networkId, Zigbee::ZigbeeBackendTypeNxp, this); + break; + } + network->setSettingsDirectory(QDir(NymeaSettings::settingsPath())); + return network; +} + +void ZigbeeManager::addNetwork(ZigbeeNetwork *network) +{ + connect(network, &ZigbeeNetwork::stateChanged, this, [this, network](ZigbeeNetwork::State state){ + qCDebug(dcZigbee()) << "Network state changed" << network->networkUuid().toString() << state; + + // TODO: set state of zigbee resource depending on the state + + emit zigbeeNetworkChanged(network); + }); + + connect(network, &ZigbeeNetwork::errorOccured, this, [network](ZigbeeNetwork::Error error){ + qCDebug(dcZigbee()) << "Network error occured for network" << network->networkUuid().toString() << error; + + // TODO: handle error + }); + + connect(network, &ZigbeeNetwork::panIdChanged, this, [this, network](quint16 panId){ + qCDebug(dcZigbee()) << "Network PAN ID changed" << network->networkUuid().toString() << panId; + saveNetwork(network); + emit zigbeeNetworkChanged(network); + }); + + connect(network, &ZigbeeNetwork::channelChanged, this, [this, network](quint8 channel){ + qCDebug(dcZigbee()) << "Network channel changed" << network->networkUuid().toString() << channel; + saveNetwork(network); + emit zigbeeNetworkChanged(network); + }); + + connect(network, &ZigbeeNetwork::securityConfigurationChanged, this, [this, network](const ZigbeeSecurityConfiguration &securityConfiguration){ + qCDebug(dcZigbee()) << "Network security configuration changed" << network->networkUuid().toString() << securityConfiguration.networkKey().toString(); + saveNetwork(network); + }); + + connect(network, &ZigbeeNetwork::channelMaskChanged, this, [this, network](const ZigbeeChannelMask &channelMask){ + qCDebug(dcZigbee()) << "Network channel mask changed" << network->networkUuid().toString() << channelMask; + saveNetwork(network); + emit zigbeeNetworkChanged(network); + }); + + m_zigbeeNetworks.insert(network->networkUuid(), network); + emit zigbeeNetworkAdded(network); } ZigbeeAdapter ZigbeeManager::createAdapterFromUartAdapter(const ZigbeeUartAdapter &uartAdapter) @@ -118,9 +266,19 @@ ZigbeeAdapter ZigbeeManager::createAdapterFromUartAdapter(const ZigbeeUartAdapte adapter.setName(uartAdapter.name()); adapter.setSystemLocation(uartAdapter.systemLocation()); adapter.setDescription(uartAdapter.description()); - adapter.setBackendSuggestionAvailable(uartAdapter.backendSuggestionAvailable()); - adapter.setSuggestedZigbeeBackendType(uartAdapter.suggestedZigbeeBackendType()); - adapter.setSuggestedBaudRate(uartAdapter.suggestedBaudRate()); + adapter.setHardwareRecognized(uartAdapter.backendSuggestionAvailable()); + adapter.setBaudRate(uartAdapter.suggestedBaudRate()); + switch (uartAdapter.suggestedZigbeeBackendType()) { + case Zigbee::ZigbeeBackendTypeDeconz: + adapter.setBackendType(ZigbeeAdapter::ZigbeeBackendTypeDeconz); + break; + case Zigbee::ZigbeeBackendTypeNxp: + adapter.setBackendType(ZigbeeAdapter::ZigbeeBackendTypeNxp); + break; + default: + qCWarning(dcZigbee()) << "Unhandled backend type" << uartAdapter.suggestedZigbeeBackendType() << "which is not implemented in nymea yet."; + break; + } return adapter; } diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index 7ec50dd8..b0c2c14a 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -44,12 +44,6 @@ class ZigbeeManager : public QObject { Q_OBJECT public: - enum ZigbeeBackendType { - ZigbeeBackendTypeDconz, - ZigbeeBackendTypeNxp - }; - Q_ENUM(ZigbeeBackendType) - enum ZigbeeNetworkState { ZigbeeNetworkStateOffline, ZigbeeNetworkStateUpdating, @@ -70,16 +64,21 @@ public: bool available() const; bool enabled() const; - ZigbeeNetwork *zigbeeNetwork() const; - ZigbeeAdapters availableAdapters(); + ZigbeeAdapters availableAdapters() const; - void createZigbeeNetwork(const QString &serialPort, qint32 baudrate, Zigbee::ZigbeeBackendType backend); + ZigbeeError createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask = ZigbeeChannelMask()); private: ZigbeeAdapters m_adapters; ZigbeeUartAdapterMonitor *m_adapterMonitor = nullptr; - ZigbeeNetwork *m_zigbeeNetwork = nullptr; + QHash m_zigbeeNetworks; + + void saveNetwork(ZigbeeNetwork *network); + void loadZigbeeNetworks(); + + ZigbeeNetwork *buildNetworkObject(const QUuid &networkId, ZigbeeAdapter::ZigbeeBackendType backendType); + void addNetwork(ZigbeeNetwork *network); ZigbeeAdapter createAdapterFromUartAdapter(const ZigbeeUartAdapter &uartAdapter); @@ -87,6 +86,8 @@ signals: void availableAdapterAdded(const ZigbeeAdapter &adapter); void availableAdapterRemoved(const ZigbeeAdapter &adapter); + void zigbeeNetworkAdded(ZigbeeNetwork *zigbeeNetwork); + void zigbeeNetworkRemoved(ZigbeeNetwork *zigbeeNetwork); void zigbeeNetworkChanged(ZigbeeNetwork *zigbeeNetwork); }; From 7585f306398bb1802732fee6a5e20a134f2d8b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 29 Oct 2020 18:12:28 +0100 Subject: [PATCH 13/54] Basic network adding and removing working --- libnymea-core/jsonrpc/zigbeehandler.cpp | 204 +++++++++++++++++------- libnymea-core/jsonrpc/zigbeehandler.h | 9 +- libnymea-core/zigbee/zigbeeadapter.cpp | 2 +- libnymea-core/zigbee/zigbeeadapter.h | 13 +- libnymea-core/zigbee/zigbeemanager.cpp | 55 ++++++- libnymea-core/zigbee/zigbeemanager.h | 11 +- 6 files changed, 220 insertions(+), 74 deletions(-) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index ee2f1480..c64bc987 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -31,6 +31,7 @@ #include "zigbeehandler.h" #include "zigbee/zigbeemanager.h" #include "zigbee/zigbeeadapters.h" +#include "loggingcategories.h" #include @@ -40,6 +41,9 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : JsonHandler(parent), m_zigbeeManager(zigbeeManager) { + qRegisterMetaType(); + qRegisterMetaType(); + registerEnum(); registerEnum(); registerEnum(); @@ -48,7 +52,16 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // Network object describing a network instance QVariantMap zigbeeNetworkDescription; - zigbeeNetworkDescription.insert("uuid", enumValueName(Uuid)); + zigbeeNetworkDescription.insert("networkUuid", enumValueName(Uuid)); + zigbeeNetworkDescription.insert("serialPort", enumValueName(String)); + zigbeeNetworkDescription.insert("baudRate", enumValueName(Uint)); + zigbeeNetworkDescription.insert("macAddress", enumValueName(String)); + zigbeeNetworkDescription.insert("panId", enumValueName(Uint)); + zigbeeNetworkDescription.insert("channel", enumValueName(Uint)); + zigbeeNetworkDescription.insert("channelMask", enumValueName(Uint)); + zigbeeNetworkDescription.insert("permitJoin", enumValueName(Bool)); + zigbeeNetworkDescription.insert("backendType", enumRef()); + zigbeeNetworkDescription.insert("networkState", enumRef()); registerObject("ZigbeeNetwork", zigbeeNetworkDescription); QVariantMap params, returns; @@ -56,7 +69,9 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // GetAdapters params.clear(); returns.clear(); - description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network on the desired serial interface. If an adapter hardware has been recognized as a supported hardware, the \'hardwareRecognized\' property will be true and the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; + description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network on the desired serial interface." + "If an adapter hardware has been recognized as a supported hardware, the \'hardwareRecognized\' property will be true and " + "the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; returns.insert("adapters", objectRef()); registerMethod("GetAdapters", description, params, returns); @@ -72,21 +87,46 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : params.insert("adapters", objectRef()); registerNotification("AdapterRemoved", description, params); + // GetNetworks params.clear(); returns.clear(); - description = "Get the status of the current network."; - returns.insert("available", enumValueName(Bool)); - returns.insert("enabled", enumValueName(Bool)); - returns.insert("configured", enumValueName(Bool)); - returns.insert("serialPort", enumValueName(String)); - returns.insert("baudRate", enumValueName(Uint)); - returns.insert("backend", enumRef()); - returns.insert("firmwareVersion", enumValueName(String)); - returns.insert("networkIeeeeAddress", enumValueName(String)); - returns.insert("networkPanId", enumValueName(Uint)); - returns.insert("channel", enumValueName(Uint)); - returns.insert("permitJoin", enumValueName(Bool)); - returns.insert("networkState", enumRef()); - registerMethod("GetNetworkStatus", description, params, returns); + description = "Returns the list of current configured zigbee networks."; + returns.insert("zigbeeNetworks", QVariantList() << objectRef("ZigbeeNetwork")); + registerMethod("GetNetworks", description, params, returns); + + // AddNetwork + params.clear(); returns.clear(); + description = "Create a new zigbee network for the given zigbee adapter. The channel mask is optional and defaults to all channels. " + "The quietest channel will be picked. The channel mask type is a TODO and will probably be a flag."; + params.insert("adapter", objectRef()); + params.insert("o:channelMask", enumValueName(Uint)); + returns.insert("zigbeeError", enumRef()); + registerMethod("AddNetwork", description, params, returns); + + // RemoveNetwork + params.clear(); returns.clear(); + description = "Remove the zigbee network with the given network uuid"; + params.insert("networkUuid", enumValueName(Uuid)); + returns.insert("zigbeeError", enumRef()); + registerMethod("RemoveNetwork", description, params, returns); + + // NetworkAdded notification + params.clear(); + description = "Emitted whenever a new ZigBee network has been added."; + params.insert("network", objectRef("ZigbeeNetwork")); + registerNotification("NetworkAdded", description, params); + + // NetworkRemoved notification + params.clear(); + description = "Emitted whenever a new ZigBee network has been removed."; + params.insert("networkUuid", enumValueName(Uuid)); + registerNotification("NetworkRemoved", description, params); + + // NetworkChanged notification + params.clear(); + description = "Emitted whenever a new ZigBee network has changed."; + params.insert("network", objectRef("ZigbeeNetwork")); + registerNotification("NetworkChanged", description, params); + connect(m_zigbeeManager, &ZigbeeManager::availableAdapterAdded, this, [this](const ZigbeeAdapter &adapter){ QVariantMap params; @@ -100,32 +140,23 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : emit AdapterRemoved(params); }); - /* 1. GetNetworks - * 2. Setup network if the is no network configured - * - GetAdapters - * - AddNetwork (adapter, channelmask) - * - - */ + connect(m_zigbeeManager, &ZigbeeManager::zigbeeNetworkAdded, this, [this](ZigbeeNetwork *network){ + QVariantMap params; + params.insert("zigbeeNetwork", packNetwork(network)); + emit NetworkAdded(params); + }); - // GetNetworkStatus - // NetworkStatusChanged - // SetupNetwork(network, uart, baudrate, backendtype) - // PermitJoin(time, o:nwk address) - // FactoryResetNetwork - - // GetNodes [Node(mac, nwkAddress, name, manufacturer, type, descriptors, associacted device, state, reachable)] - // NodeAdded - // NodeChanged (state, node base information, associated deviceId) - // RemoveNode - // NodeRemoved - - // GetGroups - // GroupChanged - // AddGroup - // GroupAdded - // RemoveGroup - // GroupRemoved + connect(m_zigbeeManager, &ZigbeeManager::zigbeeNetworkChanged, this, [this](ZigbeeNetwork *network){ + QVariantMap params; + params.insert("zigbeeNetwork", packNetwork(network)); + emit NetworkChanged(params); + }); + connect(m_zigbeeManager, &ZigbeeManager::zigbeeNetworkRemoved, this, [this](const QUuid &networkUuid){ + QVariantMap params; + params.insert("networkUuid", networkUuid.toString()); + emit NetworkRemoved(params); + }); } QString ZigbeeHandler::name() const @@ -133,26 +164,6 @@ QString ZigbeeHandler::name() const return "Zigbee"; } -JsonReply *ZigbeeHandler::GetNetworkStatus(const QVariantMap ¶ms) -{ - Q_UNUSED(params) - - QVariantMap ret; -// if (m_zigbeeManager->zigbeeNetwork()) { -// ret.insert("available", m_zigbeeManager->available()); -// ret.insert("enabled", m_zigbeeManager->enabled()); -// ret.insert("configured", true); -// ret.insert("networkState", m_zigbeeManager->zigbeeNetwork()->state()); -// } else { -// ret.insert("available", m_zigbeeManager->available()); -// ret.insert("enabled", m_zigbeeManager->enabled()); -// ret.insert("configured", false); -// ret.insert("state", ZigbeeNetwork::StateUninitialized); -// } - - return createReply(ret); -} - JsonReply *ZigbeeHandler::GetAdapters(const QVariantMap ¶ms) { Q_UNUSED(params) @@ -166,4 +177,77 @@ JsonReply *ZigbeeHandler::GetAdapters(const QVariantMap ¶ms) return createReply(returnMap); } +JsonReply *ZigbeeHandler::AddNetwork(const QVariantMap ¶ms) +{ + ZigbeeAdapter adapter = unpack(params.value("adapter")); + ZigbeeManager::ZigbeeError error = m_zigbeeManager->createZigbeeNetwork(adapter); + QVariantMap returnMap; + returnMap.insert("zigbeeError", enumValueName(error)); + return createReply(returnMap); +} + +JsonReply *ZigbeeHandler::RemoveNetwork(const QVariantMap ¶ms) +{ + QUuid networkUuid = params.value("networkUuid").toUuid(); + ZigbeeManager::ZigbeeError error = m_zigbeeManager->removeZigbeeNetwork(networkUuid); + QVariantMap returnMap; + returnMap.insert("zigbeeError", enumValueName(error)); + return createReply(returnMap); +} + +JsonReply *ZigbeeHandler::GetNetworks(const QVariantMap ¶ms) +{ + Q_UNUSED(params) + + QVariantMap returnMap; + QVariantList networkList; + foreach (ZigbeeNetwork *network, m_zigbeeManager->zigbeeNetworks().values()) { + networkList.append(packNetwork(network)); + } + returnMap.insert("zigbeeNetworks", networkList); + return createReply(returnMap); +} + +QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network) +{ + QVariantMap networkMap; + networkMap.insert("networkUuid", network->networkUuid()); + networkMap.insert("serialPort", network->serialPortName()); + networkMap.insert("baudRate", network->serialBaudrate()); + networkMap.insert("macAddress", network->macAddress().toString()); + networkMap.insert("panId", network->panId()); + networkMap.insert("channel", network->channel()); + networkMap.insert("channelMask", network->channelMask().toUInt32()); + networkMap.insert("permitJoin", network->permitJoining()); + switch (network->backendType()) { + case Zigbee::ZigbeeBackendTypeDeconz: + networkMap.insert("backendType", enumValueName(ZigbeeAdapter::ZigbeeBackendTypeDeconz)); + break; + case Zigbee::ZigbeeBackendTypeNxp: + networkMap.insert("backendType", enumValueName(ZigbeeAdapter::ZigbeeBackendTypeNxp)); + break; + } + + switch (network->state()) { + case ZigbeeNetwork::StateOffline: + case ZigbeeNetwork::StateStopping: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateOffline)); + break; + case ZigbeeNetwork::StateStarting: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateStarting)); + break; + case ZigbeeNetwork::StateRunning: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateOnline)); + break; + case ZigbeeNetwork::StateUpdating: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateUpdating)); + break; + case ZigbeeNetwork::StateUninitialized: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateError)); + break; + } + + return networkMap; +} + } diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h index 3b99035a..b7656347 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.h +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -49,8 +49,12 @@ public: QString name() const override; - Q_INVOKABLE JsonReply *GetNetworkStatus(const QVariantMap ¶ms); Q_INVOKABLE JsonReply *GetAdapters(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetNetworks(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *AddNetwork(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *RemoveNetwork(const QVariantMap ¶ms); + + QVariantMap packNetwork(ZigbeeNetwork *network); private: ZigbeeManager *m_zigbeeManager = nullptr; @@ -58,6 +62,9 @@ private: signals: void AdapterAdded(const QVariantMap ¶ms); void AdapterRemoved(const QVariantMap ¶ms); + void NetworkAdded(const QVariantMap ¶ms); + void NetworkRemoved(const QVariantMap ¶ms); + void NetworkChanged(const QVariantMap ¶ms); }; diff --git a/libnymea-core/zigbee/zigbeeadapter.cpp b/libnymea-core/zigbee/zigbeeadapter.cpp index ce1af680..27205acd 100644 --- a/libnymea-core/zigbee/zigbeeadapter.cpp +++ b/libnymea-core/zigbee/zigbeeadapter.cpp @@ -113,7 +113,7 @@ QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter) debug.nospace() << "ZigbeeAdapter(" << adapter.name() << " - " << adapter.description(); debug.nospace() << ", " << adapter.systemLocation(); if (adapter.hardwareRecognized()) { - debug.nospace() << "Hardware recognized: " << adapter.backendType(); + debug.nospace() << " Hardware recognized: " << adapter.backendType(); debug.nospace() << ", " << adapter.baudRate(); } diff --git a/libnymea-core/zigbee/zigbeeadapter.h b/libnymea-core/zigbee/zigbeeadapter.h index 08f88c18..fcc3e6ac 100644 --- a/libnymea-core/zigbee/zigbeeadapter.h +++ b/libnymea-core/zigbee/zigbeeadapter.h @@ -41,12 +41,12 @@ namespace nymeaserver { class ZigbeeAdapter { Q_GADGET - Q_PROPERTY(QString name READ name) - Q_PROPERTY(QString description READ description) - Q_PROPERTY(QString systemLocation READ systemLocation) - Q_PROPERTY(bool hardwareRecognized READ hardwareRecognized) - Q_PROPERTY(ZigbeeAdapter::ZigbeeBackendType backendType READ backendType) - Q_PROPERTY(qint32 baudRate READ baudRate) + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString description READ description WRITE setDescription) + Q_PROPERTY(QString systemLocation READ systemLocation WRITE setSystemLocation) + Q_PROPERTY(bool hardwareRecognized READ hardwareRecognized WRITE setHardwareRecognized) + Q_PROPERTY(nymeaserver::ZigbeeAdapter::ZigbeeBackendType backendType READ backendType WRITE setBackendType) + Q_PROPERTY(qint32 baudRate READ baudRate WRITE setBaudRate) public: enum ZigbeeBackendType { @@ -91,6 +91,7 @@ QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter); } Q_DECLARE_METATYPE(nymeaserver::ZigbeeAdapter) +Q_DECLARE_METATYPE(nymeaserver::ZigbeeAdapter::ZigbeeBackendType) #endif // ZIGBEEADAPTER_H diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index c3c29081..3dc5ac31 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -95,6 +95,11 @@ ZigbeeAdapters ZigbeeManager::availableAdapters() const return m_adapters; } +QHash ZigbeeManager::zigbeeNetworks() const +{ + return m_zigbeeNetworks; +} + ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask) { qCDebug(dcZigbee()) << "Start creating network for" << adapter << channelMask; @@ -124,6 +129,32 @@ ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapte return ZigbeeErrorNoError; } +ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &networkUuid) +{ + if (!m_zigbeeNetworks.keys().contains(networkUuid)) { + qCDebug(dcZigbee()) << "Could not remove network with uuid" << networkUuid.toString() << "because there is no network with this uuid."; + return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; + } + + qCDebug(dcZigbee()) << "Removing network" << networkUuid.toString(); + ZigbeeNetwork *network = m_zigbeeNetworks.take(networkUuid); + // Note: destroy will remove all nodes from the network and wipe/delete the database + network->destroyNetwork(); + emit zigbeeNetworkRemoved(network->networkUuid()); + // Make sure to delete later, so all node removed signals can be processed + network->deleteLater(); + + NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); + settings.beginGroup("ZigbeeNetworks"); + settings.beginGroup(network->networkUuid().toString()); + settings.remove(""); + settings.endGroup(); + settings.endGroup(); + + qCDebug(dcZigbee()) << "Network removed successfully" << networkUuid.toString(); + return ZigbeeManager::ZigbeeErrorNoError; +} + void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) { NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); @@ -144,7 +175,7 @@ void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) } settings.setValue("panId", network->panId()); settings.setValue("channel", network->channel()); - + settings.setValue("macAddress", network->macAddress().toString()); settings.setValue("channelMask", network->channelMask().toUInt32()); settings.setValue("networkKey", network->securityConfiguration().networkKey().toString()); settings.setValue("trustCenterLinkKey", network->securityConfiguration().globalTrustCenterLinkKey().toString()); @@ -168,7 +199,7 @@ void ZigbeeManager::loadZigbeeNetworks() quint16 panId = static_cast(settings.value("panId", 0).toUInt()); quint8 channel = settings.value("channel", 0).toUInt(); ZigbeeChannelMask channelMask = ZigbeeChannelMask(static_cast(settings.value("channelMask").toUInt())); - + ZigbeeAddress macAddress = ZigbeeAddress(settings.value("macAddress").toString()); ZigbeeSecurityConfiguration securityConfiguration; ZigbeeNetworkKey netKey(settings.value("networkKey", QString()).toString()); if (netKey.isValid()) { @@ -183,6 +214,7 @@ void ZigbeeManager::loadZigbeeNetworks() ZigbeeNetwork *network = buildNetworkObject(networkUuid, backendType); network->setSerialPortName(serialPortName); network->setSerialBaudrate(serialBaudRate); + network->setMacAddress(macAddress); network->setPanId(panId); network->setChannel(channel); network->setChannelMask(channelMask); @@ -245,6 +277,12 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) emit zigbeeNetworkChanged(network); }); + connect(network, &ZigbeeNetwork::macAddressChanged, this, [this, network](const ZigbeeAddress &macAddress){ + qCDebug(dcZigbee()) << "Network MAC address changed" << network->networkUuid().toString() << macAddress.toString(); + saveNetwork(network); + emit zigbeeNetworkChanged(network); + }); + connect(network, &ZigbeeNetwork::securityConfigurationChanged, this, [this, network](const ZigbeeSecurityConfiguration &securityConfiguration){ qCDebug(dcZigbee()) << "Network security configuration changed" << network->networkUuid().toString() << securityConfiguration.networkKey().toString(); saveNetwork(network); @@ -256,6 +294,19 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) emit zigbeeNetworkChanged(network); }); + connect(network, &ZigbeeNetwork::permitJoiningChanged, this, [this, network](bool permitJoiningChanged){ + qCDebug(dcZigbee()) << "Network permit joining changed" << network->networkUuid().toString() << permitJoiningChanged; + emit zigbeeNetworkChanged(network); + }); + + connect(network, &ZigbeeNetwork::nodeAdded, this, [network](ZigbeeNode *node){ + qCDebug(dcZigbee()) << "Network node added to network" << network->networkUuid().toString() << node; + }); + + connect(network, &ZigbeeNetwork::nodeRemoved, this, [network](ZigbeeNode *node){ + qCDebug(dcZigbee()) << "Network node removed from network" << network->networkUuid().toString() << node; + }); + m_zigbeeNetworks.insert(network->networkUuid(), network); emit zigbeeNetworkAdded(network); } diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index b0c2c14a..d75e9a9a 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -46,6 +46,7 @@ class ZigbeeManager : public QObject public: enum ZigbeeNetworkState { ZigbeeNetworkStateOffline, + ZigbeeNetworkStateStarting, ZigbeeNetworkStateUpdating, ZigbeeNetworkStateOnline, ZigbeeNetworkStateError @@ -55,7 +56,8 @@ public: enum ZigbeeError { ZigbeeErrorNoError, ZigbeeErrorAdapterNotAvailable, - ZigbeeErrorAdapterAlreadyInUse + ZigbeeErrorAdapterAlreadyInUse, + ZigbeeErrorNetworkUuidNotFound }; Q_ENUM(ZigbeeError) @@ -65,13 +67,14 @@ public: bool enabled() const; ZigbeeAdapters availableAdapters() const; + QHash zigbeeNetworks() const; - ZigbeeError createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask = ZigbeeChannelMask()); + ZigbeeError createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); + ZigbeeError removeZigbeeNetwork(const QUuid &networkUuid); private: ZigbeeAdapters m_adapters; ZigbeeUartAdapterMonitor *m_adapterMonitor = nullptr; - QHash m_zigbeeNetworks; void saveNetwork(ZigbeeNetwork *network); @@ -87,7 +90,7 @@ signals: void availableAdapterRemoved(const ZigbeeAdapter &adapter); void zigbeeNetworkAdded(ZigbeeNetwork *zigbeeNetwork); - void zigbeeNetworkRemoved(ZigbeeNetwork *zigbeeNetwork); + void zigbeeNetworkRemoved(const QUuid networkUuid); void zigbeeNetworkChanged(ZigbeeNetwork *zigbeeNetwork); }; From 6edf6977a424f5c3ee8cc920b7d1766a2087071f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sun, 1 Nov 2020 22:16:57 +0100 Subject: [PATCH 14/54] Add factory reset network and start implementing permit join mechanism --- libnymea-core/jsonrpc/zigbeehandler.cpp | 66 ++++++++++++++++++++++--- libnymea-core/jsonrpc/zigbeehandler.h | 2 + libnymea-core/zigbee/zigbeemanager.cpp | 59 ++++++++++++++++++---- libnymea-core/zigbee/zigbeemanager.h | 7 ++- 4 files changed, 115 insertions(+), 19 deletions(-) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index c64bc987..4f84f53c 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -56,6 +56,7 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : zigbeeNetworkDescription.insert("serialPort", enumValueName(String)); zigbeeNetworkDescription.insert("baudRate", enumValueName(Uint)); zigbeeNetworkDescription.insert("macAddress", enumValueName(String)); + zigbeeNetworkDescription.insert("firmwareVersion", enumValueName(String)); zigbeeNetworkDescription.insert("panId", enumValueName(Uint)); zigbeeNetworkDescription.insert("channel", enumValueName(Uint)); zigbeeNetworkDescription.insert("channelMask", enumValueName(Uint)); @@ -69,9 +70,11 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // GetAdapters params.clear(); returns.clear(); - description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network on the desired serial interface." - "If an adapter hardware has been recognized as a supported hardware, the \'hardwareRecognized\' property will be true and " - "the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; + description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network " + "on the desired serial interface. If an adapter hardware has been recognized as a supported " + "hardware, the \'hardwareRecognized\' property will be true and the serial port and backend " + "configurations can be used as they where given, otherwise the user might set the backend " + "type and baud rate manually."; returns.insert("adapters", objectRef()); registerMethod("GetAdapters", description, params, returns); @@ -84,19 +87,22 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // AdapterRemoved notification params.clear(); description = "Emitted whenever a ZigBee adapter has been removed from the system (i.e. unplugged)."; - params.insert("adapters", objectRef()); + params.insert("adapter", objectRef()); registerNotification("AdapterRemoved", description, params); // GetNetworks params.clear(); returns.clear(); - description = "Returns the list of current configured zigbee networks."; + description = "Returns the list of zigbee networks configured in the system."; returns.insert("zigbeeNetworks", QVariantList() << objectRef("ZigbeeNetwork")); registerMethod("GetNetworks", description, params, returns); // AddNetwork params.clear(); returns.clear(); - description = "Create a new zigbee network for the given zigbee adapter. The channel mask is optional and defaults to all channels. " - "The quietest channel will be picked. The channel mask type is a TODO and will probably be a flag."; + description = "Create a new zigbee network for the given zigbee adapter. " + "The channel mask is optional and defaults to all channels [11, 26]. " + "The quietest channel will be picked after a channel scan. " + "The channel mask is a uint32 flag and the the bit number represents the channel which should " + "enabled for scanning. All channels would be the value 0x07fff800."; params.insert("adapter", objectRef()); params.insert("o:channelMask", enumValueName(Uint)); returns.insert("zigbeeError", enumRef()); @@ -127,6 +133,28 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : params.insert("network", objectRef("ZigbeeNetwork")); registerNotification("NetworkChanged", description, params); + // FactoryResetNetwork + params.clear(); returns.clear(); + description = "Factory reset the network with the given networkUuid. The network does not have " + "to be Online for this procedure, and all associated nodes and things will be removed permanently. " + "Make sure the user realy wants to do this because this can not be undone."; + params.insert("networkUuid", enumValueName(Uuid)); + returns.insert("zigbeeError", enumRef()); + registerMethod("FactoryResetNetwork", description, params, returns); + + // SetPermitJoin + params.clear(); returns.clear(); + description = "Allow or deny nodes to join the network with the given networkUuid for a specific duration in seconds. " + "If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. " + "The shortAddress is optional and defaults to the broadcast address (0xfffc) for all routers in the network. " + "If the short address matches the address of a router node in the network, only that router will " + "be able to allow new nodes to join the network. A new node will join to the router with the best LQI."; + params.insert("networkUuid", enumValueName(Uuid)); + params.insert("timeout", enumValueName(Uint)); + params.insert("o:shortAddress", enumValueName(Uint)); + returns.insert("zigbeeError", enumRef()); + registerMethod("SetPermitJoin", description, params, returns); + connect(m_zigbeeManager, &ZigbeeManager::availableAdapterAdded, this, [this](const ZigbeeAdapter &adapter){ QVariantMap params; @@ -195,6 +223,29 @@ JsonReply *ZigbeeHandler::RemoveNetwork(const QVariantMap ¶ms) return createReply(returnMap); } +JsonReply *ZigbeeHandler::FactoryResetNetwork(const QVariantMap ¶ms) +{ + QUuid networkUuid = params.value("networkUuid").toUuid(); + ZigbeeManager::ZigbeeError error = m_zigbeeManager->factoryResetNetwork(networkUuid); + QVariantMap returnMap; + returnMap.insert("zigbeeError", enumValueName(error)); + return createReply(returnMap); +} + +JsonReply *ZigbeeHandler::SetPermitJoin(const QVariantMap ¶ms) +{ + QUuid networkUuid = params.value("networkUuid").toUuid(); + uint duration = params.value("duration").toUInt(); + quint16 shortAddress = static_cast(Zigbee::BroadcastAddressAllRouters); + if (params.contains("shortAddress")) { + shortAddress = static_cast(params.value("shortAddress").toUInt()); + } + ZigbeeManager::ZigbeeError error = m_zigbeeManager->setZigbeeNetworkPermitJoin(networkUuid, shortAddress, duration); + QVariantMap returnMap; + returnMap.insert("zigbeeError", enumValueName(error)); + return createReply(returnMap); +} + JsonReply *ZigbeeHandler::GetNetworks(const QVariantMap ¶ms) { Q_UNUSED(params) @@ -215,6 +266,7 @@ QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network) networkMap.insert("serialPort", network->serialPortName()); networkMap.insert("baudRate", network->serialBaudrate()); networkMap.insert("macAddress", network->macAddress().toString()); + networkMap.insert("firmwareVersion", network->firmwareVersion()); networkMap.insert("panId", network->panId()); networkMap.insert("channel", network->channel()); networkMap.insert("channelMask", network->channelMask().toUInt32()); diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h index b7656347..a5c6b614 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.h +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -53,6 +53,8 @@ public: Q_INVOKABLE JsonReply *GetNetworks(const QVariantMap ¶ms); Q_INVOKABLE JsonReply *AddNetwork(const QVariantMap ¶ms); Q_INVOKABLE JsonReply *RemoveNetwork(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *FactoryResetNetwork(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *SetPermitJoin(const QVariantMap ¶ms); QVariantMap packNetwork(ZigbeeNetwork *network); diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 3dc5ac31..77424340 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -32,6 +32,8 @@ #include "nymeasettings.h" #include "loggingcategories.h" +#include + NYMEA_LOGGING_CATEGORY(dcZigbee, "Zigbee") // Register debug category from the libnymea-zigbee @@ -52,13 +54,13 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : qCDebug(dcZigbee()) << "Loading initial adapter list"; foreach(const ZigbeeUartAdapter &uartAdapter, m_adapterMonitor->availableAdapters()) { - ZigbeeAdapter adapter = createAdapterFromUartAdapter(uartAdapter); + ZigbeeAdapter adapter = convertUartAdapterToAdapter(uartAdapter); qCDebug(dcZigbee()) << "Adapter added" << adapter; m_adapters.append(adapter); } connect(m_adapterMonitor, &ZigbeeUartAdapterMonitor::adapterAdded, this, [this](const ZigbeeUartAdapter &uartAdapter){ - ZigbeeAdapter adapter = createAdapterFromUartAdapter(uartAdapter); + ZigbeeAdapter adapter = convertUartAdapterToAdapter(uartAdapter); qCDebug(dcZigbee()) << "Adapter added" << adapter; m_adapters.append(adapter); emit availableAdapterAdded(adapter); @@ -107,7 +109,7 @@ ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapte // Make sure we don't have aleardy a network for this adapter foreach (ZigbeeNetwork *existingNetwork, m_zigbeeNetworks.values()) { if (existingNetwork->serialPortName() == adapter.systemLocation()) { - qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "which is already in use for network" << existingNetwork->networkUuid().toString(); + qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "because this adapter is already in use for network" << existingNetwork->networkUuid().toString(); return ZigbeeManager::ZigbeeErrorAdapterAlreadyInUse; } } @@ -132,7 +134,7 @@ ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapte ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &networkUuid) { if (!m_zigbeeNetworks.keys().contains(networkUuid)) { - qCDebug(dcZigbee()) << "Could not remove network with uuid" << networkUuid.toString() << "because there is no network with this uuid."; + qCWarning(dcZigbee()) << "Could not remove network with uuid" << networkUuid.toString() << "because there is no network with this uuid."; return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; } @@ -144,6 +146,7 @@ ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &netwo // Make sure to delete later, so all node removed signals can be processed network->deleteLater(); + // Delete network settings NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); settings.beginGroup("ZigbeeNetworks"); settings.beginGroup(network->networkUuid().toString()); @@ -155,6 +158,37 @@ ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &netwo return ZigbeeManager::ZigbeeErrorNoError; } +ZigbeeManager::ZigbeeError ZigbeeManager::setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress, int duration) +{ + if (!m_zigbeeNetworks.keys().contains(networkUuid)) { + qCWarning(dcZigbee()) << "Could not set permit join network" << networkUuid.toString() << "because there is no network with this uuid."; + return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; + } + + ZigbeeNetwork *network = m_zigbeeNetworks.value(networkUuid); + if (network->state() != ZigbeeNetwork::StateRunning) { + qCWarning(dcZigbee()) << "Could not set permit join network" << networkUuid.toString() << "because the network is not running."; + return ZigbeeManager::ZigbeeErrorNetworkOffline; + } + + // TODO: set permit join + + qCDebug(dcZigbee()) << "Set permit join for network" << networkUuid.toString() << ZigbeeUtils::convertUint16ToHexString(shortAddress) << "to" << duration << "[s] successfully."; + return ZigbeeManager::ZigbeeErrorNoError; +} + +ZigbeeManager::ZigbeeError ZigbeeManager::factoryResetNetwork(const QUuid &networkUuid) +{ + if (!m_zigbeeNetworks.keys().contains(networkUuid)) { + qCWarning(dcZigbee()) << "Could not factory reset network with uuid" << networkUuid.toString() << "because there is no network with this uuid."; + return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; + } + + ZigbeeNetwork *network = m_zigbeeNetworks.value(networkUuid); + network->factoryResetNetwork(); + return ZigbeeManager::ZigbeeErrorNoError; +} + void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) { NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); @@ -260,7 +294,7 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) }); connect(network, &ZigbeeNetwork::errorOccured, this, [network](ZigbeeNetwork::Error error){ - qCDebug(dcZigbee()) << "Network error occured for network" << network->networkUuid().toString() << error; + qCWarning(dcZigbee()) << "Network error occured for network" << network->networkUuid().toString() << error; // TODO: handle error }); @@ -307,19 +341,24 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) qCDebug(dcZigbee()) << "Network node removed from network" << network->networkUuid().toString() << node; }); + connect(network, &ZigbeeNetwork::firmwareVersionChanged, this, [this, network](const QString &firmwareVersion){ + qCDebug(dcZigbee()) << "Network adapter firmware version changed" << network->networkUuid().toString() << firmwareVersion; + emit zigbeeNetworkChanged(network); + }); + m_zigbeeNetworks.insert(network->networkUuid(), network); emit zigbeeNetworkAdded(network); } -ZigbeeAdapter ZigbeeManager::createAdapterFromUartAdapter(const ZigbeeUartAdapter &uartAdapter) +ZigbeeAdapter ZigbeeManager::convertUartAdapterToAdapter(const ZigbeeUartAdapter &uartAdapter) { ZigbeeAdapter adapter; adapter.setName(uartAdapter.name()); adapter.setSystemLocation(uartAdapter.systemLocation()); adapter.setDescription(uartAdapter.description()); - adapter.setHardwareRecognized(uartAdapter.backendSuggestionAvailable()); - adapter.setBaudRate(uartAdapter.suggestedBaudRate()); - switch (uartAdapter.suggestedZigbeeBackendType()) { + adapter.setHardwareRecognized(uartAdapter.hardwareRecognized()); + adapter.setBaudRate(uartAdapter.baudRate()); + switch (uartAdapter.zigbeeBackend()) { case Zigbee::ZigbeeBackendTypeDeconz: adapter.setBackendType(ZigbeeAdapter::ZigbeeBackendTypeDeconz); break; @@ -327,7 +366,7 @@ ZigbeeAdapter ZigbeeManager::createAdapterFromUartAdapter(const ZigbeeUartAdapte adapter.setBackendType(ZigbeeAdapter::ZigbeeBackendTypeNxp); break; default: - qCWarning(dcZigbee()) << "Unhandled backend type" << uartAdapter.suggestedZigbeeBackendType() << "which is not implemented in nymea yet."; + qCWarning(dcZigbee()) << "Unhandled backend type" << uartAdapter.zigbeeBackend() << "which is not implemented in nymea yet."; break; } return adapter; diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index d75e9a9a..d01d8053 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -57,7 +57,8 @@ public: ZigbeeErrorNoError, ZigbeeErrorAdapterNotAvailable, ZigbeeErrorAdapterAlreadyInUse, - ZigbeeErrorNetworkUuidNotFound + ZigbeeErrorNetworkUuidNotFound, + ZigbeeErrorNetworkOffline }; Q_ENUM(ZigbeeError) @@ -71,6 +72,8 @@ public: ZigbeeError createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); ZigbeeError removeZigbeeNetwork(const QUuid &networkUuid); + ZigbeeError setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, int duration = 120); + ZigbeeError factoryResetNetwork(const QUuid &networkUuid); private: ZigbeeAdapters m_adapters; @@ -83,7 +86,7 @@ private: ZigbeeNetwork *buildNetworkObject(const QUuid &networkId, ZigbeeAdapter::ZigbeeBackendType backendType); void addNetwork(ZigbeeNetwork *network); - ZigbeeAdapter createAdapterFromUartAdapter(const ZigbeeUartAdapter &uartAdapter); + ZigbeeAdapter convertUartAdapterToAdapter(const ZigbeeUartAdapter &uartAdapter); signals: void availableAdapterAdded(const ZigbeeAdapter &adapter); From cdf8b171f955f84a912da76180ec0b5ca0c457f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 2 Nov 2020 15:13:42 +0100 Subject: [PATCH 15/54] Finish zigbee network joining as first version --- libnymea-core/jsonrpc/zigbeehandler.cpp | 16 ++++++-- libnymea-core/zigbee/zigbeemanager.cpp | 50 +++++++++++++++---------- libnymea-core/zigbee/zigbeemanager.h | 3 +- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 4f84f53c..654e754b 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -60,7 +60,9 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : zigbeeNetworkDescription.insert("panId", enumValueName(Uint)); zigbeeNetworkDescription.insert("channel", enumValueName(Uint)); zigbeeNetworkDescription.insert("channelMask", enumValueName(Uint)); - zigbeeNetworkDescription.insert("permitJoin", enumValueName(Bool)); + zigbeeNetworkDescription.insert("permitJoinEnabled", enumValueName(Bool)); + zigbeeNetworkDescription.insert("permitJoinDuration", enumValueName(Uint)); + zigbeeNetworkDescription.insert("permitJoinRemaining", enumValueName(Uint)); zigbeeNetworkDescription.insert("backendType", enumRef()); zigbeeNetworkDescription.insert("networkState", enumRef()); registerObject("ZigbeeNetwork", zigbeeNetworkDescription); @@ -145,12 +147,15 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // SetPermitJoin params.clear(); returns.clear(); description = "Allow or deny nodes to join the network with the given networkUuid for a specific duration in seconds. " + "The duration values has to be between 0 and 255 seconds. The permitJoinDuration indicates how long permit " + "has been enabled and the permitJoinDuration indicates the rest of the time. Those values can be used to " + "show a countdown or progressbar. This method can be recalled for resetting the timeout. " "If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. " "The shortAddress is optional and defaults to the broadcast address (0xfffc) for all routers in the network. " "If the short address matches the address of a router node in the network, only that router will " - "be able to allow new nodes to join the network. A new node will join to the router with the best LQI."; + "be able to allow new nodes to join the network. A new node will join to the router with the best link quality index (LQI)."; params.insert("networkUuid", enumValueName(Uuid)); - params.insert("timeout", enumValueName(Uint)); + params.insert("duration", enumValueName(Uint)); params.insert("o:shortAddress", enumValueName(Uint)); returns.insert("zigbeeError", enumRef()); registerMethod("SetPermitJoin", description, params, returns); @@ -270,7 +275,10 @@ QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network) networkMap.insert("panId", network->panId()); networkMap.insert("channel", network->channel()); networkMap.insert("channelMask", network->channelMask().toUInt32()); - networkMap.insert("permitJoin", network->permitJoining()); + networkMap.insert("permitJoinEnabled", network->permitJoiningEnabled()); + networkMap.insert("permitJoinDuration", network->permitJoiningDuration()); + networkMap.insert("permitJoinRemaining", network->permitJoiningRemaining()); + switch (network->backendType()) { case Zigbee::ZigbeeBackendTypeDeconz: networkMap.insert("backendType", enumValueName(ZigbeeAdapter::ZigbeeBackendTypeDeconz)); diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 77424340..beb54cd5 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -109,7 +109,7 @@ ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapte // Make sure we don't have aleardy a network for this adapter foreach (ZigbeeNetwork *existingNetwork, m_zigbeeNetworks.values()) { if (existingNetwork->serialPortName() == adapter.systemLocation()) { - qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "because this adapter is already in use for network" << existingNetwork->networkUuid().toString(); + qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "because this adapter is already in use for network" << existingNetwork; return ZigbeeManager::ZigbeeErrorAdapterAlreadyInUse; } } @@ -125,7 +125,7 @@ ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapte network->setSerialBaudrate(adapter.baudRate()); addNetwork(network); - qCDebug(dcZigbee()) << "Starting zigbee network" << network->networkUuid().toString(); + qCDebug(dcZigbee()) << "Starting" << network; network->startNetwork(); return ZigbeeErrorNoError; @@ -138,8 +138,8 @@ ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &netwo return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; } - qCDebug(dcZigbee()) << "Removing network" << networkUuid.toString(); ZigbeeNetwork *network = m_zigbeeNetworks.take(networkUuid); + qCDebug(dcZigbee()) << "Removing" << network; // Note: destroy will remove all nodes from the network and wipe/delete the database network->destroyNetwork(); emit zigbeeNetworkRemoved(network->networkUuid()); @@ -154,26 +154,34 @@ ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &netwo settings.endGroup(); settings.endGroup(); - qCDebug(dcZigbee()) << "Network removed successfully" << networkUuid.toString(); + qCDebug(dcZigbee()) << "Network removed successfully"; return ZigbeeManager::ZigbeeErrorNoError; } -ZigbeeManager::ZigbeeError ZigbeeManager::setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress, int duration) +ZigbeeManager::ZigbeeError ZigbeeManager::setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress, uint duration) { if (!m_zigbeeNetworks.keys().contains(networkUuid)) { qCWarning(dcZigbee()) << "Could not set permit join network" << networkUuid.toString() << "because there is no network with this uuid."; return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; } + if (duration > 255) { + qCWarning(dcZigbee()) << "The given duration for permit join is out of range. Only values between 0 and 255 are allowed."; + return ZigbeeManager::ZigbeeErrorDurationOutOfRange; + } + ZigbeeNetwork *network = m_zigbeeNetworks.value(networkUuid); if (network->state() != ZigbeeNetwork::StateRunning) { - qCWarning(dcZigbee()) << "Could not set permit join network" << networkUuid.toString() << "because the network is not running."; + qCWarning(dcZigbee()) << "Could not set permit join in" << network << "because the network is not running."; return ZigbeeManager::ZigbeeErrorNetworkOffline; } - // TODO: set permit join + qCDebug(dcZigbee()) << "Set permit joining in network" << network << "to" << duration << "seconds" << ZigbeeUtils::convertUint16ToHexString(shortAddress); + network->setPermitJoining(duration, shortAddress); + + // Notify all clients about the new configuration + emit zigbeeNetworkChanged(network); - qCDebug(dcZigbee()) << "Set permit join for network" << networkUuid.toString() << ZigbeeUtils::convertUint16ToHexString(shortAddress) << "to" << duration << "[s] successfully."; return ZigbeeManager::ZigbeeErrorNoError; } @@ -185,6 +193,7 @@ ZigbeeManager::ZigbeeError ZigbeeManager::factoryResetNetwork(const QUuid &netwo } ZigbeeNetwork *network = m_zigbeeNetworks.value(networkUuid); + qCDebug(dcZigbee()) << "Start factory resetting" << network; network->factoryResetNetwork(); return ZigbeeManager::ZigbeeErrorNoError; } @@ -221,8 +230,8 @@ void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) void ZigbeeManager::loadZigbeeNetworks() { NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); + qCDebug(dcZigbee()) << "Loading zigbee networks from" << settings.fileName(); settings.beginGroup("ZigbeeNetworks"); - foreach (const QString networkUuidGroupString, settings.childGroups()) { settings.beginGroup(networkUuidGroupString); @@ -260,6 +269,7 @@ void ZigbeeManager::loadZigbeeNetworks() if (m_zigbeeNetworks.isEmpty()) { qCDebug(dcZigbee()) << "There are no zigbee networks configured yet."; + return; } // Start all loaded networks @@ -294,55 +304,55 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) }); connect(network, &ZigbeeNetwork::errorOccured, this, [network](ZigbeeNetwork::Error error){ - qCWarning(dcZigbee()) << "Network error occured for network" << network->networkUuid().toString() << error; + qCWarning(dcZigbee()) << "Network error occured for" << network << error; // TODO: handle error }); connect(network, &ZigbeeNetwork::panIdChanged, this, [this, network](quint16 panId){ - qCDebug(dcZigbee()) << "Network PAN ID changed" << network->networkUuid().toString() << panId; + qCDebug(dcZigbee()) << "Network PAN ID changed for" << network << panId; saveNetwork(network); emit zigbeeNetworkChanged(network); }); connect(network, &ZigbeeNetwork::channelChanged, this, [this, network](quint8 channel){ - qCDebug(dcZigbee()) << "Network channel changed" << network->networkUuid().toString() << channel; + qCDebug(dcZigbee()) << "Network channel changed for" << network << channel; saveNetwork(network); emit zigbeeNetworkChanged(network); }); connect(network, &ZigbeeNetwork::macAddressChanged, this, [this, network](const ZigbeeAddress &macAddress){ - qCDebug(dcZigbee()) << "Network MAC address changed" << network->networkUuid().toString() << macAddress.toString(); + qCDebug(dcZigbee()) << "Network MAC address changed for" << network << macAddress.toString(); saveNetwork(network); emit zigbeeNetworkChanged(network); }); connect(network, &ZigbeeNetwork::securityConfigurationChanged, this, [this, network](const ZigbeeSecurityConfiguration &securityConfiguration){ - qCDebug(dcZigbee()) << "Network security configuration changed" << network->networkUuid().toString() << securityConfiguration.networkKey().toString(); + qCDebug(dcZigbee()) << "Network security configuration changed for" << network << securityConfiguration.networkKey().toString() << securityConfiguration.globalTrustCenterLinkKey().toString(); saveNetwork(network); }); connect(network, &ZigbeeNetwork::channelMaskChanged, this, [this, network](const ZigbeeChannelMask &channelMask){ - qCDebug(dcZigbee()) << "Network channel mask changed" << network->networkUuid().toString() << channelMask; + qCDebug(dcZigbee()) << "Network channel mask changed for" << network << channelMask; saveNetwork(network); emit zigbeeNetworkChanged(network); }); - connect(network, &ZigbeeNetwork::permitJoiningChanged, this, [this, network](bool permitJoiningChanged){ - qCDebug(dcZigbee()) << "Network permit joining changed" << network->networkUuid().toString() << permitJoiningChanged; + connect(network, &ZigbeeNetwork::permitJoiningEnabledChanged, this, [this, network](bool permitJoiningEnabled){ + qCDebug(dcZigbee()) << "Network permit joining changed" << network->networkUuid().toString() << permitJoiningEnabled; emit zigbeeNetworkChanged(network); }); connect(network, &ZigbeeNetwork::nodeAdded, this, [network](ZigbeeNode *node){ - qCDebug(dcZigbee()) << "Network node added to network" << network->networkUuid().toString() << node; + qCDebug(dcZigbee()) << "Node added to" << network << node; }); connect(network, &ZigbeeNetwork::nodeRemoved, this, [network](ZigbeeNode *node){ - qCDebug(dcZigbee()) << "Network node removed from network" << network->networkUuid().toString() << node; + qCDebug(dcZigbee()) << "Node removed from" << network->networkUuid().toString() << node; }); connect(network, &ZigbeeNetwork::firmwareVersionChanged, this, [this, network](const QString &firmwareVersion){ - qCDebug(dcZigbee()) << "Network adapter firmware version changed" << network->networkUuid().toString() << firmwareVersion; + qCDebug(dcZigbee()) << "Network adapter firmware version changed for" << network << firmwareVersion; emit zigbeeNetworkChanged(network); }); diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index d01d8053..39b088f2 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -58,6 +58,7 @@ public: ZigbeeErrorAdapterNotAvailable, ZigbeeErrorAdapterAlreadyInUse, ZigbeeErrorNetworkUuidNotFound, + ZigbeeErrorDurationOutOfRange, ZigbeeErrorNetworkOffline }; Q_ENUM(ZigbeeError) @@ -72,7 +73,7 @@ public: ZigbeeError createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); ZigbeeError removeZigbeeNetwork(const QUuid &networkUuid); - ZigbeeError setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, int duration = 120); + ZigbeeError setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, uint duration = 120); ZigbeeError factoryResetNetwork(const QUuid &networkUuid); private: From c3508acc2345f5811b6d7297ed0b50d3bccd1a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 2 Nov 2020 16:02:54 +0100 Subject: [PATCH 16/54] Pass nodes into the zigbee resource and implement available for resource --- .../zigbeehardwareresourceimplementation.cpp | 65 ++++++++++--------- .../zigbeehardwareresourceimplementation.h | 17 +++-- .../hardwaremanagerimplementation.cpp | 12 ++-- libnymea-core/hardwaremanagerimplementation.h | 7 +- libnymea-core/nymeacore.cpp | 2 +- libnymea-core/zigbee/zigbeemanager.cpp | 33 ++++++++-- libnymea-core/zigbee/zigbeemanager.h | 6 ++ libnymea/hardwaremanager.h | 2 +- 8 files changed, 84 insertions(+), 60 deletions(-) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index f459a4f2..1eb4adff 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -41,15 +41,18 @@ NYMEA_LOGGING_CATEGORY(dcZigbeeResource, "ZigbeeResource") namespace nymeaserver { -ZigbeeHardwareResourceImplementation::ZigbeeHardwareResourceImplementation(QObject *parent) : - ZigbeeHardwareResource(parent) +ZigbeeHardwareResourceImplementation::ZigbeeHardwareResourceImplementation(ZigbeeManager *zigbeeManager, QObject *parent) : + ZigbeeHardwareResource(parent), + m_zigbeeManager(zigbeeManager) { - + connect(m_zigbeeManager, &ZigbeeManager::nodeAdded, this, &ZigbeeHardwareResourceImplementation::onZigbeeNodeAdded); + connect(m_zigbeeManager, &ZigbeeManager::nodeRemoved, this, &ZigbeeHardwareResourceImplementation::onZigbeeNodeRemoved); + connect(m_zigbeeManager, &ZigbeeManager::availableChanged, this, &ZigbeeHardwareResourceImplementation::onZigbeeAvailableChanged); } bool ZigbeeHardwareResourceImplementation::available() const { - return m_available; + return m_zigbeeManager->available(); } bool ZigbeeHardwareResourceImplementation::enabled() const @@ -57,18 +60,6 @@ bool ZigbeeHardwareResourceImplementation::enabled() const return m_enabled; } -void ZigbeeHardwareResourceImplementation::setZigbeeNetwork(ZigbeeNetwork *network) -{ - // Clean up - if (m_zigbeeNetwork) { - disconnect(m_zigbeeNetwork, &ZigbeeNetwork::stateChanged, this, &ZigbeeHardwareResourceImplementation::onZigbeeNetworkStateChanged); - } - - // Set new network - m_zigbeeNetwork = network; - connect(m_zigbeeNetwork, &ZigbeeNetwork::stateChanged, this, &ZigbeeHardwareResourceImplementation::onZigbeeNetworkStateChanged); -} - void ZigbeeHardwareResourceImplementation::setEnabled(bool enabled) { qCDebug(dcZigbeeResource()) << "Set" << (enabled ? "enabled" : "disabled"); @@ -93,33 +84,43 @@ void ZigbeeHardwareResourceImplementation::setEnabled(bool enabled) } } -void ZigbeeHardwareResourceImplementation::onZigbeeNetworkStateChanged(ZigbeeNetwork::State state) -{ - qCDebug(dcZigbeeResource()) << "Network state changed" << state; -} - bool ZigbeeHardwareResourceImplementation::enable() { - qCDebug(dcZigbeeResource()) << "Enable hardware resource"; + qCDebug(dcZigbeeResource()) << "Enable hardware resource. Not implemented yet."; - if (!m_zigbeeNetwork) { - qCDebug(dcZigbeeResource()) << "There is no zigbee network configured as hardware resource"; - } else { - // TODO: start network - } + // TODO: enable all networks in the zigbee manager return true; } bool ZigbeeHardwareResourceImplementation::disable() { - qCDebug(dcZigbeeResource()) << "Disable hardware resource"; - if (!m_zigbeeNetwork) { - qCDebug(dcZigbeeResource()) << "There is no zigbee network configured as hardware resource"; - } + qCDebug(dcZigbeeResource()) << "Disable hardware resource. Not implemented yet."; + + // TODO: disable all networks in the zigbee manager - // TODO: stop network return true; } +void ZigbeeHardwareResourceImplementation::onZigbeeAvailableChanged(bool available) +{ + if (available) { + qCDebug(dcZigbeeResource()) << "Zigbee is now available"; + } else { + qCWarning(dcZigbeeResource()) << "Zigbee is not available any more"; + } + + emit availableChanged(available); +} + +void ZigbeeHardwareResourceImplementation::onZigbeeNodeAdded(const QUuid &networkUuid, ZigbeeNode *node) +{ + qCDebug(dcZigbeeResource()) << node << "joined the network" << m_zigbeeManager->zigbeeNetworks().value(networkUuid); +} + +void ZigbeeHardwareResourceImplementation::onZigbeeNodeRemoved(const QUuid &networkUuid, ZigbeeNode *node) +{ + qCDebug(dcZigbeeResource()) << node << "left the network" << m_zigbeeManager->zigbeeNetworks().value(networkUuid); +} + } diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h index ab29f96b..480826cb 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h @@ -33,7 +33,7 @@ #include -#include "zigbeenetwork.h" +#include "zigbee/zigbeemanager.h" #include "hardware/zigbee/zigbeehardwarereource.h" namespace nymeaserver { @@ -43,29 +43,28 @@ class ZigbeeHardwareResourceImplementation : public ZigbeeHardwareResource Q_OBJECT public: - explicit ZigbeeHardwareResourceImplementation(QObject *parent = nullptr); + explicit ZigbeeHardwareResourceImplementation(ZigbeeManager *zigbeeManager, QObject *parent = nullptr); bool available() const override; bool enabled() const override; - void setZigbeeNetwork(ZigbeeNetwork *network); - private: bool m_available = false; bool m_enabled = false; - - ZigbeeNetwork *m_zigbeeNetwork = nullptr; + ZigbeeManager *m_zigbeeManager = nullptr; protected: void setEnabled(bool enabled) override; -private slots: - void onZigbeeNetworkStateChanged(ZigbeeNetwork::State state); - public slots: bool enable(); bool disable(); +private slots: + void onZigbeeAvailableChanged(bool available); + void onZigbeeNodeAdded(const QUuid &networkUuid, ZigbeeNode *node); + void onZigbeeNodeRemoved(const QUuid &networkUuid, ZigbeeNode *node); + }; } diff --git a/libnymea-core/hardwaremanagerimplementation.cpp b/libnymea-core/hardwaremanagerimplementation.cpp index 6a804dcb..0222c86f 100644 --- a/libnymea-core/hardwaremanagerimplementation.cpp +++ b/libnymea-core/hardwaremanagerimplementation.cpp @@ -46,7 +46,7 @@ namespace nymeaserver { -HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, QObject *parent) : +HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, ZigbeeManager *zigbeeManager, QObject *parent) : HardwareManager(parent), m_platform(platform) { @@ -71,10 +71,7 @@ HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform, m_i2cManager = new I2CManagerImplementation(this); - m_zigbeeManager = new ZigbeeHardwareResourceImplementation(this); - - qCDebug(dcHardware()) << "Hardware manager initialized successfully"; - + m_zigbeeResource = new ZigbeeHardwareResourceImplementation(zigbeeManager, this); // Enable all the resources setResourceEnabled(m_pluginTimerManager, true); @@ -93,6 +90,7 @@ HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform, setResourceEnabled(m_bluetoothLowEnergyManager, true); m_mqttProvider = new MqttProviderImplementation(mqttBroker, this); + qCDebug(dcHardware()) << "Hardware manager initialized successfully"; } HardwareManagerImplementation::~HardwareManagerImplementation() @@ -139,9 +137,9 @@ I2CManager *HardwareManagerImplementation::i2cManager() return m_i2cManager; } -ZigbeeHardwareResource *HardwareManagerImplementation::zigbeeManager() +ZigbeeHardwareResource *HardwareManagerImplementation::zigbeeResource() { - return m_zigbeeManager; + return m_zigbeeResource; } } diff --git a/libnymea-core/hardwaremanagerimplementation.h b/libnymea-core/hardwaremanagerimplementation.h index 3094d3d0..9e807803 100644 --- a/libnymea-core/hardwaremanagerimplementation.h +++ b/libnymea-core/hardwaremanagerimplementation.h @@ -41,13 +41,14 @@ namespace nymeaserver { class Platform; class MqttBroker; +class ZigbeeManager; class HardwareManagerImplementation : public HardwareManager { Q_OBJECT public: - explicit HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, QObject *parent = nullptr); + explicit HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, ZigbeeManager *zigbeeManager, QObject *parent = nullptr); ~HardwareManagerImplementation() override; Radio433 *radio433() override; @@ -58,7 +59,7 @@ public: BluetoothLowEnergyManager *bluetoothLowEnergyManager() override; MqttProvider *mqttProvider() override; I2CManager *i2cManager() override; - ZigbeeHardwareResource *zigbeeManager() override; + ZigbeeHardwareResource *zigbeeResource() override; private: QNetworkAccessManager *m_networkAccessManager = nullptr; @@ -73,7 +74,7 @@ private: BluetoothLowEnergyManager *m_bluetoothLowEnergyManager = nullptr; MqttProvider *m_mqttProvider = nullptr; I2CManager *m_i2cManager = nullptr; - ZigbeeHardwareResource *m_zigbeeManager = nullptr; + ZigbeeHardwareResource *m_zigbeeResource = nullptr; }; } diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index 33f94b9b..f2fc3e58 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -110,7 +110,7 @@ void NymeaCore::init() { m_zigbeeManager = new ZigbeeManager(this); qCDebug(dcCore) << "Creating Hardware Manager"; - m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), this); + m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), m_zigbeeManager, this); qCDebug(dcCore) << "Creating Thing Manager (locale:" << m_configuration->locale() << ")"; m_thingManager = new ThingManagerImplementation(m_hardwareManager, m_configuration->locale(), this); diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index beb54cd5..980dbd74 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -84,7 +84,7 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : bool ZigbeeManager::available() const { - return !m_zigbeeNetworks.isEmpty(); + return m_available; } bool ZigbeeManager::enabled() const @@ -296,16 +296,15 @@ ZigbeeNetwork *ZigbeeManager::buildNetworkObject(const QUuid &networkId, ZigbeeA void ZigbeeManager::addNetwork(ZigbeeNetwork *network) { connect(network, &ZigbeeNetwork::stateChanged, this, [this, network](ZigbeeNetwork::State state){ - qCDebug(dcZigbee()) << "Network state changed" << network->networkUuid().toString() << state; - - // TODO: set state of zigbee resource depending on the state - + Q_UNUSED(state) + qCDebug(dcZigbee()) << "Network state changed" << network; + evaluateZigbeeAvailable(); emit zigbeeNetworkChanged(network); }); - connect(network, &ZigbeeNetwork::errorOccured, this, [network](ZigbeeNetwork::Error error){ + connect(network, &ZigbeeNetwork::errorOccured, this, [this, network](ZigbeeNetwork::Error error){ qCWarning(dcZigbee()) << "Network error occured for" << network << error; - + evaluateZigbeeAvailable(); // TODO: handle error }); @@ -382,4 +381,24 @@ ZigbeeAdapter ZigbeeManager::convertUartAdapterToAdapter(const ZigbeeUartAdapter return adapter; } +void ZigbeeManager::evaluateZigbeeAvailable() +{ + bool zigbeeAvailable = false; + if (!m_zigbeeNetworks.isEmpty()) { + foreach (ZigbeeNetwork *network, m_zigbeeNetworks.values()) { + if (network->state() == ZigbeeNetwork::StateRunning) { + zigbeeAvailable = true; + break; + } + } + } + + if (m_available == zigbeeAvailable) + return; + + qCDebug(dcZigbee()) << "Zigbee is" << (zigbeeAvailable ? "now available" : "not available any more."); + m_available = zigbeeAvailable; + emit availableChanged(m_available); +} + } diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index 39b088f2..84c81131 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -80,6 +80,7 @@ private: ZigbeeAdapters m_adapters; ZigbeeUartAdapterMonitor *m_adapterMonitor = nullptr; QHash m_zigbeeNetworks; + bool m_available = false; void saveNetwork(ZigbeeNetwork *network); void loadZigbeeNetworks(); @@ -88,8 +89,11 @@ private: void addNetwork(ZigbeeNetwork *network); ZigbeeAdapter convertUartAdapterToAdapter(const ZigbeeUartAdapter &uartAdapter); + void evaluateZigbeeAvailable(); signals: + void availableChanged(bool available); + void availableAdapterAdded(const ZigbeeAdapter &adapter); void availableAdapterRemoved(const ZigbeeAdapter &adapter); @@ -97,6 +101,8 @@ signals: void zigbeeNetworkRemoved(const QUuid networkUuid); void zigbeeNetworkChanged(ZigbeeNetwork *zigbeeNetwork); + void nodeAdded(const QUuid &networkUuid, ZigbeeNode *node); + void nodeRemoved(const QUuid &networkUuid, ZigbeeNode *node); }; } diff --git a/libnymea/hardwaremanager.h b/libnymea/hardwaremanager.h index 2e384d90..745a4ca9 100644 --- a/libnymea/hardwaremanager.h +++ b/libnymea/hardwaremanager.h @@ -62,7 +62,7 @@ public: virtual BluetoothLowEnergyManager *bluetoothLowEnergyManager() = 0; virtual MqttProvider *mqttProvider() = 0; virtual I2CManager *i2cManager() = 0; - virtual ZigbeeHardwareResource *zigbeeManager() = 0; + virtual ZigbeeHardwareResource *zigbeeResource() = 0; protected: void setResourceEnabled(HardwareResource* resource, bool enabled); From ee00d31ce5949840ea587ec02bc0bf80b9edde64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 2 Nov 2020 16:31:08 +0100 Subject: [PATCH 17/54] Add node added and removed signals into the zigbee manager without the coordinator node --- libnymea-core/zigbee/zigbeemanager.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 980dbd74..5c472dd5 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -342,12 +342,22 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) emit zigbeeNetworkChanged(network); }); - connect(network, &ZigbeeNetwork::nodeAdded, this, [network](ZigbeeNode *node){ + connect(network, &ZigbeeNetwork::nodeAdded, this, [this, network](ZigbeeNode *node){ qCDebug(dcZigbee()) << "Node added to" << network << node; + // The plugin don't need to see the coordinator node + if (node->shortAddress() == 0) { + return; + } + emit nodeAdded(network->networkUuid(), node); }); - connect(network, &ZigbeeNetwork::nodeRemoved, this, [network](ZigbeeNode *node){ + connect(network, &ZigbeeNetwork::nodeRemoved, this, [this, network](ZigbeeNode *node){ qCDebug(dcZigbee()) << "Node removed from" << network->networkUuid().toString() << node; + // The plugin don't need to see the coordinator node + if (node->shortAddress() == 0) { + return; + } + emit nodeRemoved(network->networkUuid(), node); }); connect(network, &ZigbeeNetwork::firmwareVersionChanged, this, [this, network](const QString &firmwareVersion){ From 5ed9769427ad975f6cafb1c997d87b67038b4972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 2 Nov 2020 17:26:02 +0100 Subject: [PATCH 18/54] Fix network added/removed notification parameter name --- libnymea-core/jsonrpc/zigbeehandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 654e754b..02f19273 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -120,7 +120,7 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // NetworkAdded notification params.clear(); description = "Emitted whenever a new ZigBee network has been added."; - params.insert("network", objectRef("ZigbeeNetwork")); + params.insert("zigbeeNetwork", objectRef("ZigbeeNetwork")); registerNotification("NetworkAdded", description, params); // NetworkRemoved notification @@ -132,7 +132,7 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // NetworkChanged notification params.clear(); description = "Emitted whenever a new ZigBee network has changed."; - params.insert("network", objectRef("ZigbeeNetwork")); + params.insert("zigbeeNetwork", objectRef("ZigbeeNetwork")); registerNotification("NetworkChanged", description, params); // FactoryResetNetwork From 203badf0c741ef87d412ed4900f3df4d54a977e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 5 Nov 2020 15:35:45 +0100 Subject: [PATCH 19/54] Improve zigbee api and add serial number --- libnymea-core/jsonrpc/zigbeehandler.cpp | 54 +++++++++++++++---------- libnymea-core/zigbee/zigbeeadapter.cpp | 22 +++++++--- libnymea-core/zigbee/zigbeeadapter.h | 13 ++++-- libnymea-core/zigbee/zigbeeadapters.cpp | 11 +++++ libnymea-core/zigbee/zigbeeadapters.h | 1 + libnymea-core/zigbee/zigbeemanager.cpp | 46 ++++++++++++--------- libnymea-core/zigbee/zigbeemanager.h | 2 +- libnymea/interfaces/alert.json | 2 +- libnymea/interfaces/gateway.json | 2 +- 9 files changed, 100 insertions(+), 53 deletions(-) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 02f19273..3d3cf18f 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -60,9 +60,9 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : zigbeeNetworkDescription.insert("panId", enumValueName(Uint)); zigbeeNetworkDescription.insert("channel", enumValueName(Uint)); zigbeeNetworkDescription.insert("channelMask", enumValueName(Uint)); - zigbeeNetworkDescription.insert("permitJoinEnabled", enumValueName(Bool)); - zigbeeNetworkDescription.insert("permitJoinDuration", enumValueName(Uint)); - zigbeeNetworkDescription.insert("permitJoinRemaining", enumValueName(Uint)); + zigbeeNetworkDescription.insert("permitJoiningEnabled", enumValueName(Bool)); + zigbeeNetworkDescription.insert("permitJoiningDuration", enumValueName(Uint)); + zigbeeNetworkDescription.insert("permitJoiningRemaining", enumValueName(Uint)); zigbeeNetworkDescription.insert("backendType", enumRef()); zigbeeNetworkDescription.insert("networkState", enumRef()); registerObject("ZigbeeNetwork", zigbeeNetworkDescription); @@ -72,9 +72,10 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // GetAdapters params.clear(); returns.clear(); - description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network " - "on the desired serial interface. If an adapter hardware has been recognized as a supported " - "hardware, the \'hardwareRecognized\' property will be true and the serial port and backend " + description = "Get the list of available Zigbee adapter candidates in order to set up the zigbee network " + "on the desired serial interface. The serialPort property can be used as unique identifier. " + "If an adapter hardware has been recognized as a supported " + "hardware, the \'hardwareRecognized\' property will be true and the baud rate and backend " "configurations can be used as they where given, otherwise the user might set the backend " "type and baud rate manually."; returns.insert("adapters", objectRef()); @@ -82,13 +83,13 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // AdapterAdded notification params.clear(); - description = "Emitted whenever a new ZigBee adapter candidate has been detected in the system."; + description = "Emitted whenever a new Zigbee adapter candidate has been detected in the system."; params.insert("adapter", objectRef()); registerNotification("AdapterAdded", description, params); // AdapterRemoved notification params.clear(); - description = "Emitted whenever a ZigBee adapter has been removed from the system (i.e. unplugged)."; + description = "Emitted whenever a Zigbee adapter has been removed from the system (i.e. unplugged)."; params.insert("adapter", objectRef()); registerNotification("AdapterRemoved", description, params); @@ -100,38 +101,42 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // AddNetwork params.clear(); returns.clear(); - description = "Create a new zigbee network for the given zigbee adapter. " + description = "Create a new Zigbee network for the given serialPort, baud rate and backend type. " + "Get those information from the available Zigbee adapters." "The channel mask is optional and defaults to all channels [11, 26]. " - "The quietest channel will be picked after a channel scan. " + "The quietest channel from the given channel mask will be picked during network creation. " "The channel mask is a uint32 flag and the the bit number represents the channel which should " "enabled for scanning. All channels would be the value 0x07fff800."; - params.insert("adapter", objectRef()); + params.insert("serialPort", enumValueName(String)); + params.insert("baudRate", enumValueName(Uint)); + params.insert("backendType", enumRef()); params.insert("o:channelMask", enumValueName(Uint)); returns.insert("zigbeeError", enumRef()); + returns.insert("o:networkUuid", enumValueName(Uuid)); registerMethod("AddNetwork", description, params, returns); // RemoveNetwork params.clear(); returns.clear(); - description = "Remove the zigbee network with the given network uuid"; + description = "Remove the zigbee network with the given network uuid."; params.insert("networkUuid", enumValueName(Uuid)); returns.insert("zigbeeError", enumRef()); registerMethod("RemoveNetwork", description, params, returns); // NetworkAdded notification params.clear(); - description = "Emitted whenever a new ZigBee network has been added."; + description = "Emitted whenever a new Zigbee network has been added."; params.insert("zigbeeNetwork", objectRef("ZigbeeNetwork")); registerNotification("NetworkAdded", description, params); // NetworkRemoved notification params.clear(); - description = "Emitted whenever a new ZigBee network has been removed."; + description = "Emitted whenever a new Zigbee network has been removed."; params.insert("networkUuid", enumValueName(Uuid)); registerNotification("NetworkRemoved", description, params); // NetworkChanged notification params.clear(); - description = "Emitted whenever a new ZigBee network has changed."; + description = "Emitted whenever a new Zigbee network has changed."; params.insert("zigbeeNetwork", objectRef("ZigbeeNetwork")); registerNotification("NetworkChanged", description, params); @@ -187,7 +192,7 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : connect(m_zigbeeManager, &ZigbeeManager::zigbeeNetworkRemoved, this, [this](const QUuid &networkUuid){ QVariantMap params; - params.insert("networkUuid", networkUuid.toString()); + params.insert("networkUuid", networkUuid); emit NetworkRemoved(params); }); } @@ -212,10 +217,15 @@ JsonReply *ZigbeeHandler::GetAdapters(const QVariantMap ¶ms) JsonReply *ZigbeeHandler::AddNetwork(const QVariantMap ¶ms) { - ZigbeeAdapter adapter = unpack(params.value("adapter")); - ZigbeeManager::ZigbeeError error = m_zigbeeManager->createZigbeeNetwork(adapter); + QString serialPort = params.value("serialPort").toString(); + uint baudRate = params.value("baudRate").toUInt(); + ZigbeeAdapter::ZigbeeBackendType backendType = enumNameToValue(params.value("backendType").toString()); + QPair result = m_zigbeeManager->createZigbeeNetwork(serialPort, baudRate, backendType); QVariantMap returnMap; - returnMap.insert("zigbeeError", enumValueName(error)); + if (result.first == ZigbeeManager::ZigbeeErrorNoError) { + returnMap.insert("networkUuid", result.second); + } + returnMap.insert("zigbeeError", enumValueName(result.first)); return createReply(returnMap); } @@ -275,9 +285,9 @@ QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network) networkMap.insert("panId", network->panId()); networkMap.insert("channel", network->channel()); networkMap.insert("channelMask", network->channelMask().toUInt32()); - networkMap.insert("permitJoinEnabled", network->permitJoiningEnabled()); - networkMap.insert("permitJoinDuration", network->permitJoiningDuration()); - networkMap.insert("permitJoinRemaining", network->permitJoiningRemaining()); + networkMap.insert("permitJoiningEnabled", network->permitJoiningEnabled()); + networkMap.insert("permitJoiningDuration", network->permitJoiningDuration()); + networkMap.insert("permitJoiningRemaining", network->permitJoiningRemaining()); switch (network->backendType()) { case Zigbee::ZigbeeBackendTypeDeconz: diff --git a/libnymea-core/zigbee/zigbeeadapter.cpp b/libnymea-core/zigbee/zigbeeadapter.cpp index 27205acd..4b67b52b 100644 --- a/libnymea-core/zigbee/zigbeeadapter.cpp +++ b/libnymea-core/zigbee/zigbeeadapter.cpp @@ -57,14 +57,24 @@ void ZigbeeAdapter::setDescription(const QString &description) m_description = description; } -QString ZigbeeAdapter::systemLocation() const +QString ZigbeeAdapter::serialPort() const { - return m_systemLocation; + return m_serialPort; } -void ZigbeeAdapter::setSystemLocation(const QString &systemLocation) +void ZigbeeAdapter::setSerialPort(const QString &serialPort) { - m_systemLocation = systemLocation; + m_serialPort = serialPort; +} + +QString ZigbeeAdapter::serialNumber() const +{ + return m_serialNumber; +} + +void ZigbeeAdapter::setSerialNumber(const QString &serialNumber) +{ + m_serialNumber = serialNumber; } bool ZigbeeAdapter::hardwareRecognized() const @@ -99,7 +109,7 @@ void ZigbeeAdapter::setBaudRate(qint32 baudRate) bool ZigbeeAdapter::operator==(const ZigbeeAdapter &other) const { - return m_systemLocation == other.systemLocation() + return m_serialPort == other.serialPort() && m_name == other.name() && m_description == other.description() && m_hardwareRecognized == other.hardwareRecognized() @@ -111,7 +121,7 @@ bool ZigbeeAdapter::operator==(const ZigbeeAdapter &other) const QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter) { debug.nospace() << "ZigbeeAdapter(" << adapter.name() << " - " << adapter.description(); - debug.nospace() << ", " << adapter.systemLocation(); + debug.nospace() << ", " << adapter.serialPort(); if (adapter.hardwareRecognized()) { debug.nospace() << " Hardware recognized: " << adapter.backendType(); debug.nospace() << ", " << adapter.baudRate(); diff --git a/libnymea-core/zigbee/zigbeeadapter.h b/libnymea-core/zigbee/zigbeeadapter.h index fcc3e6ac..5712c728 100644 --- a/libnymea-core/zigbee/zigbeeadapter.h +++ b/libnymea-core/zigbee/zigbeeadapter.h @@ -43,7 +43,8 @@ class ZigbeeAdapter Q_GADGET Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(QString description READ description WRITE setDescription) - Q_PROPERTY(QString systemLocation READ systemLocation WRITE setSystemLocation) + Q_PROPERTY(QString serialPort READ serialPort WRITE setSerialPort) + Q_PROPERTY(QString serialNumber READ serialNumber WRITE setSerialNumber) Q_PROPERTY(bool hardwareRecognized READ hardwareRecognized WRITE setHardwareRecognized) Q_PROPERTY(nymeaserver::ZigbeeAdapter::ZigbeeBackendType backendType READ backendType WRITE setBackendType) Q_PROPERTY(qint32 baudRate READ baudRate WRITE setBaudRate) @@ -63,8 +64,11 @@ public: QString description() const; void setDescription(const QString &description); - QString systemLocation() const; - void setSystemLocation(const QString &systemLocation); + QString serialPort() const; + void setSerialPort(const QString &serialPort); + + QString serialNumber() const; + void setSerialNumber(const QString &serialNumber); bool hardwareRecognized() const; void setHardwareRecognized(bool hardwareRecognized); @@ -80,7 +84,8 @@ public: private: QString m_name; QString m_description; - QString m_systemLocation; + QString m_serialPort; + QString m_serialNumber; bool m_hardwareRecognized = false; ZigbeeAdapter::ZigbeeBackendType m_backendType = ZigbeeAdapter::ZigbeeBackendTypeDeconz; qint32 m_baudRate = 38400; diff --git a/libnymea-core/zigbee/zigbeeadapters.cpp b/libnymea-core/zigbee/zigbeeadapters.cpp index 7379fd2a..b7408069 100644 --- a/libnymea-core/zigbee/zigbeeadapters.cpp +++ b/libnymea-core/zigbee/zigbeeadapters.cpp @@ -43,6 +43,17 @@ ZigbeeAdapters::ZigbeeAdapters(const QList &other) : } +bool ZigbeeAdapters::hasSerialPort(const QString &serialPort) +{ + for (int i = 0; i < count(); i++) { + if (at(i).serialPort() == serialPort) { + return true; + } + } + + return false; +} + QVariant ZigbeeAdapters::get(int index) const { return QVariant::fromValue(at(index)); diff --git a/libnymea-core/zigbee/zigbeeadapters.h b/libnymea-core/zigbee/zigbeeadapters.h index 05528e86..303d7a4e 100644 --- a/libnymea-core/zigbee/zigbeeadapters.h +++ b/libnymea-core/zigbee/zigbeeadapters.h @@ -45,6 +45,7 @@ class ZigbeeAdapters : public QList public: ZigbeeAdapters(); ZigbeeAdapters(const QList &other); + bool hasSerialPort(const QString &serialPort); Q_INVOKABLE QVariant get(int index) const; Q_INVOKABLE void put(const QVariant &variant); }; diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 5c472dd5..cfce0fb7 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -45,10 +45,10 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : QObject(parent) { // Adapter monitor - qCDebug(dcZigbee()) << "Initialize the ZigBee manager"; + qCDebug(dcZigbee()) << "Initialize the Zigbee manager"; m_adapterMonitor = new ZigbeeUartAdapterMonitor(this); if (!m_adapterMonitor->isValid()) { - qCWarning(dcZigbee()) << "Could not initialize the ZigBee adapter monitor."; + qCWarning(dcZigbee()) << "Could not initialize the Zigbee adapter monitor."; // Lets continue anyways, maybe we can set up existing networks right the way. } @@ -63,12 +63,15 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : ZigbeeAdapter adapter = convertUartAdapterToAdapter(uartAdapter); qCDebug(dcZigbee()) << "Adapter added" << adapter; m_adapters.append(adapter); + + // FIXME: check if serial number available and gets used by a network (adjust serial port if changed) + emit availableAdapterAdded(adapter); }); connect(m_adapterMonitor, &ZigbeeUartAdapterMonitor::adapterRemoved, this, [this](const ZigbeeUartAdapter &uartAdapter){ foreach (const ZigbeeAdapter &adapter, m_adapters) { - if (adapter.systemLocation() == uartAdapter.systemLocation()) { + if (adapter.serialPort() == uartAdapter.serialPort()) { qCDebug(dcZigbee()) << "Adapter removed" << adapter; m_adapters.removeAll(adapter); emit availableAdapterRemoved(adapter); @@ -102,33 +105,33 @@ QHash ZigbeeManager::zigbeeNetworks() const return m_zigbeeNetworks; } -ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask) +QPair ZigbeeManager::createZigbeeNetwork(const QString &serialPort, const uint baudRate, const ZigbeeAdapter::ZigbeeBackendType backendType, const ZigbeeChannelMask channelMask) { - qCDebug(dcZigbee()) << "Start creating network for" << adapter << channelMask; + qCDebug(dcZigbee()) << "Start creating network for" << serialPort << baudRate << backendType << channelMask; // Make sure we don't have aleardy a network for this adapter foreach (ZigbeeNetwork *existingNetwork, m_zigbeeNetworks.values()) { - if (existingNetwork->serialPortName() == adapter.systemLocation()) { - qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "because this adapter is already in use for network" << existingNetwork; - return ZigbeeManager::ZigbeeErrorAdapterAlreadyInUse; + if (existingNetwork->serialPortName() == serialPort) { + qCWarning(dcZigbee()) << "Failed to create a network for" << serialPort << "because this adapter is already in use for network" << existingNetwork; + return QPair(ZigbeeManager::ZigbeeErrorAdapterAlreadyInUse, QUuid()); } } - if (!m_adapters.contains(adapter)) { - qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "because the adapter is not available any more"; - return ZigbeeManager::ZigbeeErrorAdapterNotAvailable; + + if (!m_adapters.hasSerialPort(serialPort)) { + qCWarning(dcZigbee()) << "Failed to create a network for" << serialPort << "because the adapter is not available any more"; + return QPair(ZigbeeManager::ZigbeeErrorAdapterNotAvailable, QUuid()); } - ZigbeeNetwork *network = buildNetworkObject(QUuid::createUuid(), adapter.backendType()); + ZigbeeNetwork *network = buildNetworkObject(QUuid::createUuid(), backendType); network->setChannelMask(channelMask); - network->setSerialPortName(adapter.systemLocation()); - network->setSerialBaudrate(adapter.baudRate()); + network->setSerialPortName(serialPort); + network->setSerialBaudrate(baudRate); addNetwork(network); qCDebug(dcZigbee()) << "Starting" << network; network->startNetwork(); - - return ZigbeeErrorNoError; + return QPair(ZigbeeManager::ZigbeeErrorNoError, network->networkUuid()); } ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &networkUuid) @@ -138,12 +141,14 @@ ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &netwo return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; } - ZigbeeNetwork *network = m_zigbeeNetworks.take(networkUuid); + ZigbeeNetwork *network = m_zigbeeNetworks.value(networkUuid); qCDebug(dcZigbee()) << "Removing" << network; // Note: destroy will remove all nodes from the network and wipe/delete the database network->destroyNetwork(); emit zigbeeNetworkRemoved(network->networkUuid()); + // Make sure to delete later, so all node removed signals can be processed + m_zigbeeNetworks.remove(networkUuid); network->deleteLater(); // Delete network settings @@ -223,6 +228,8 @@ void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) settings.setValue("networkKey", network->securityConfiguration().networkKey().toString()); settings.setValue("trustCenterLinkKey", network->securityConfiguration().globalTrustCenterLinkKey().toString()); + // FIXME: save also the serial number of the port if available. + settings.endGroup(); // networkUuid settings.endGroup(); // ZigbeeNetworks } @@ -235,6 +242,8 @@ void ZigbeeManager::loadZigbeeNetworks() foreach (const QString networkUuidGroupString, settings.childGroups()) { settings.beginGroup(networkUuidGroupString); + // FIXME: load also the serial number of the port if available and search that serial port + QUuid networkUuid = QUuid(networkUuidGroupString); QString serialPortName = settings.value("serialPort").toString(); qint32 serialBaudRate = settings.value("baudRate").toInt(); @@ -373,8 +382,9 @@ ZigbeeAdapter ZigbeeManager::convertUartAdapterToAdapter(const ZigbeeUartAdapter { ZigbeeAdapter adapter; adapter.setName(uartAdapter.name()); - adapter.setSystemLocation(uartAdapter.systemLocation()); + adapter.setSerialPort(uartAdapter.serialPort()); adapter.setDescription(uartAdapter.description()); + adapter.setSerialNumber(uartAdapter.serialNumber()); adapter.setHardwareRecognized(uartAdapter.hardwareRecognized()); adapter.setBaudRate(uartAdapter.baudRate()); switch (uartAdapter.zigbeeBackend()) { diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index 84c81131..be796203 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -71,7 +71,7 @@ public: ZigbeeAdapters availableAdapters() const; QHash zigbeeNetworks() const; - ZigbeeError createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); + QPair createZigbeeNetwork(const QString &serialPort, const uint baudRate, const ZigbeeAdapter::ZigbeeBackendType backendType, const ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); ZigbeeError removeZigbeeNetwork(const QUuid &networkUuid); ZigbeeError setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, uint duration = 120); ZigbeeError factoryResetNetwork(const QUuid &networkUuid); diff --git a/libnymea/interfaces/alert.json b/libnymea/interfaces/alert.json index bdebb170..65d01763 100644 --- a/libnymea/interfaces/alert.json +++ b/libnymea/interfaces/alert.json @@ -1,5 +1,5 @@ { - "description": "Used for things that have some sort of alert. For instance, light bulbs may be able to blink on alert actions, or speaker might be able to play an alert sound. ZigBee devices for example oftion provide alert actions to identify themselves.", + "description": "Used for things that have some sort of alert. For instance, light bulbs may be able to blink on alert actions, or speaker might be able to play an alert sound. Zigbee devices for example oftion provide alert actions to identify themselves.", "actions": [ { "name": "alert" diff --git a/libnymea/interfaces/gateway.json b/libnymea/interfaces/gateway.json index 9ae8633a..032442c4 100644 --- a/libnymea/interfaces/gateway.json +++ b/libnymea/interfaces/gateway.json @@ -1,4 +1,4 @@ { - "description": "The gateway interface is used for gateway devices like bridges to other networks. For instance Ethernet to ZigBee bridges, Ethernet to RF bridges or similar. Typically such device classes implement the actual functionality in child devices that will auto-appear after successful connection to the gateway/bridge.", + "description": "The gateway interface is used for gateway devices like bridges to other networks. For instance Ethernet to Zigbee bridges, Ethernet to RF bridges or similar. Typically such device classes implement the actual functionality in child devices that will auto-appear after successful connection to the gateway/bridge.", "extends": "connectable" } From b6a6371021326a320898ab1add01ab1eec93db7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 5 Nov 2020 16:43:03 +0100 Subject: [PATCH 20/54] Add enabled property for network as dummy for future implementation --- libnymea-core/jsonrpc/zigbeehandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index 3d3cf18f..dc8f45ac 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -53,6 +53,7 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // Network object describing a network instance QVariantMap zigbeeNetworkDescription; zigbeeNetworkDescription.insert("networkUuid", enumValueName(Uuid)); + zigbeeNetworkDescription.insert("enabled", enumValueName(Bool)); zigbeeNetworkDescription.insert("serialPort", enumValueName(String)); zigbeeNetworkDescription.insert("baudRate", enumValueName(Uint)); zigbeeNetworkDescription.insert("macAddress", enumValueName(String)); @@ -278,6 +279,7 @@ QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network) { QVariantMap networkMap; networkMap.insert("networkUuid", network->networkUuid()); + networkMap.insert("enabled", true); // FIXME: set actual value once supported networkMap.insert("serialPort", network->serialPortName()); networkMap.insert("baudRate", network->serialBaudrate()); networkMap.insert("macAddress", network->macAddress().toString()); From 5d467de47d6774f4a85454cded5a0c5d2728e28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 Nov 2020 18:11:56 +0100 Subject: [PATCH 21/54] Introduce centralized node initializer for unified network behaviour --- libnymea-core/libnymea-core.pro | 6 +- libnymea-core/zigbee/zigbeemanager.cpp | 18 +++- libnymea-core/zigbee/zigbeemanager.h | 3 + .../zigbee/zigbeenodeinitializer.cpp | 82 +++++++++++++++++++ libnymea-core/zigbee/zigbeenodeinitializer.h | 56 +++++++++++++ 5 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 libnymea-core/zigbee/zigbeenodeinitializer.cpp create mode 100644 libnymea-core/zigbee/zigbeenodeinitializer.h diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 08365605..bcb2b87a 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -132,7 +132,8 @@ HEADERS += nymeacore.h \ platform/platform.h \ \ zigbee/zigbeeadapter.h \ zigbee/zigbeeadapters.h \ - zigbee/zigbeemanager.h + zigbee/zigbeemanager.h \ + zigbee/zigbeenodeinitializer.h SOURCES += nymeacore.cpp \ @@ -220,7 +221,8 @@ SOURCES += nymeacore.cpp \ platform/platform.cpp \ zigbee/zigbeeadapter.cpp \ zigbee/zigbeeadapters.cpp \ - zigbee/zigbeemanager.cpp + zigbee/zigbeemanager.cpp \ + zigbee/zigbeenodeinitializer.cpp versionAtLeast(QT_VERSION, 5.12.0) { diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index cfce0fb7..ae5337c0 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -82,7 +82,8 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : // Load zigbee networks from settings loadZigbeeNetworks(); - // TODO: load platform configuration for networks we know for sure how they work + // TODO: load platform configuration for networks we know for sure how they work after loading already configured networks + } bool ZigbeeManager::available() const @@ -357,7 +358,11 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) if (node->shortAddress() == 0) { return; } - emit nodeAdded(network->networkUuid(), node); + + ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); + nodeInitializer->initializeNode(node); + + //emit nodeAdded(network->networkUuid(), node); }); connect(network, &ZigbeeNetwork::nodeRemoved, this, [this, network](ZigbeeNode *node){ @@ -376,6 +381,15 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) m_zigbeeNetworks.insert(network->networkUuid(), network); emit zigbeeNetworkAdded(network); + + // Create node initializer when a new node joins the network + ZigbeeNodeInitializer *nodeInitializer = new ZigbeeNodeInitializer(network, this); + connect(nodeInitializer, &ZigbeeNodeInitializer::nodeInitialized, this, [this, network](ZigbeeNode *node){ + qCDebug(dcZigbee()) << "Node initialied from nymea" << node; + emit nodeAdded(network->networkUuid(), node); + }); + + m_zigbeeNodeInitializers.insert(network->networkUuid(), nodeInitializer); } ZigbeeAdapter ZigbeeManager::convertUartAdapterToAdapter(const ZigbeeUartAdapter &uartAdapter) diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index be796203..d235727d 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -37,6 +37,7 @@ #include #include "zigbeeadapters.h" +#include "zigbeenodeinitializer.h" namespace nymeaserver { @@ -80,6 +81,8 @@ private: ZigbeeAdapters m_adapters; ZigbeeUartAdapterMonitor *m_adapterMonitor = nullptr; QHash m_zigbeeNetworks; + QHash m_zigbeeNodeInitializers; + bool m_available = false; void saveNetwork(ZigbeeNetwork *network); diff --git a/libnymea-core/zigbee/zigbeenodeinitializer.cpp b/libnymea-core/zigbee/zigbeenodeinitializer.cpp new file mode 100644 index 00000000..96b48cfe --- /dev/null +++ b/libnymea-core/zigbee/zigbeenodeinitializer.cpp @@ -0,0 +1,82 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 "zigbeenodeinitializer.h" +#include "loggingcategories.h" + +#include + +Q_DECLARE_LOGGING_CATEGORY(dcZigbee) + +ZigbeeNodeInitializer::ZigbeeNodeInitializer(ZigbeeNetwork *network, QObject *parent) : + QObject(parent), + m_network(network) +{ + +} + +void ZigbeeNodeInitializer::initializeNode(ZigbeeNode *node) +{ + qCDebug(dcZigbee()) << "Start initializing node internally" << node; + + // Initialize and configure server clusters + foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { + + // Read values + if (endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { + + } + + foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { + switch (cluster->clusterId()) { + case ZigbeeClusterLibrary::ClusterIdPowerConfiguration: { + // Read values + + + + // Configure attribute reporting + + break; + } + default: + // Not handeld, leave it to the plugin + break; + } + + + } + } + + + // Initialize and configure client clusters + + + +} diff --git a/libnymea-core/zigbee/zigbeenodeinitializer.h b/libnymea-core/zigbee/zigbeenodeinitializer.h new file mode 100644 index 00000000..7bfe5304 --- /dev/null +++ b/libnymea-core/zigbee/zigbeenodeinitializer.h @@ -0,0 +1,56 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 . +* +* 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 ZIGBEENODEINITIALIZER_H +#define ZIGBEENODEINITIALIZER_H + +#include + +class ZigbeeNode; +class ZigbeeNetwork; + +class ZigbeeNodeInitializer : public QObject +{ + Q_OBJECT +public: + explicit ZigbeeNodeInitializer(ZigbeeNetwork *network, QObject *parent = nullptr); + + void initializeNode(ZigbeeNode *node); + +private: + ZigbeeNetwork *m_network = nullptr; + + + +signals: + void nodeInitialized(ZigbeeNode *node); +}; + +#endif // ZIGBEENODEINITIALIZER_H From 91d3ecbbf54fa260515d21baaeb5a97de1f4ef48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 Nov 2020 18:57:19 +0100 Subject: [PATCH 22/54] User NYMEA_LOGGING_CATEGORY for zigbee --- libnymea/loggingcategories.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libnymea/loggingcategories.h b/libnymea/loggingcategories.h index ec0d5251..dfb88212 100644 --- a/libnymea/loggingcategories.h +++ b/libnymea/loggingcategories.h @@ -91,8 +91,6 @@ Q_DECLARE_LOGGING_CATEGORY(dcCoap) Q_DECLARE_LOGGING_CATEGORY(dcI2C) Q_DECLARE_LOGGING_CATEGORY(dcIntegrations) Q_DECLARE_LOGGING_CATEGORY(dcJsIntegrations) -Q_DECLARE_LOGGING_CATEGORY(dcZigbee) -Q_DECLARE_LOGGING_CATEGORY(dcZigbeeResource) /* From 033d62a98d27d59b1d39eb221840f3bebd9136cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 Nov 2020 19:04:52 +0100 Subject: [PATCH 23/54] Fix double header and cpp definition due to rebase error --- libnymea-core/libnymea-core.pro | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index bcb2b87a..4017be9b 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -1,3 +1,4 @@ + TEMPLATE = lib TARGET = nymea-core @@ -37,7 +38,6 @@ RESOURCES += $$top_srcdir/icons.qrc \ HEADERS += nymeacore.h \ integrations/apikeysprovidersloader.h \ - hardware/zigbee/zigbeehardwareresourceimplementation.h \ integrations/plugininfocache.h \ integrations/python/pynymealogginghandler.h \ integrations/python/pynymeamodule.h \ @@ -138,7 +138,6 @@ HEADERS += nymeacore.h \ SOURCES += nymeacore.cpp \ integrations/apikeysprovidersloader.cpp \ - hardware/zigbee/zigbeehardwareresourceimplementation.cpp \ integrations/plugininfocache.cpp \ integrations/thingmanagerimplementation.cpp \ integrations/translator.cpp \ From af09702c31151bfa87daf215153e135a1ee469f1 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 29 Oct 2020 11:10:01 +0100 Subject: [PATCH 24/54] first stab on the adding a plugin api --- .../zigbeehardwareresourceimplementation.cpp | 40 +++++++++++++++++++ .../zigbeehardwareresourceimplementation.h | 21 ++++++---- libnymea/hardware/zigbee/zigbeehandler.cpp | 6 +++ libnymea/hardware/zigbee/zigbeehandler.h | 16 ++++++++ ...reource.cpp => zigbeehardwareresource.cpp} | 2 +- ...warereource.h => zigbeehardwareresource.h} | 18 +++++++++ libnymea/libnymea.pro | 6 ++- 7 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 libnymea/hardware/zigbee/zigbeehandler.cpp create mode 100644 libnymea/hardware/zigbee/zigbeehandler.h rename libnymea/hardware/zigbee/{zigbeehardwarereource.cpp => zigbeehardwareresource.cpp} (97%) rename libnymea/hardware/zigbee/{zigbeehardwarereource.h => zigbeehardwareresource.h} (74%) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index 1eb4adff..cab84283 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -31,6 +31,7 @@ #include "zigbeehardwareresourceimplementation.h" #include "loggingcategories.h" #include "nymeasettings.h" +#include "hardware/zigbee/zigbeehandler.h" #include #include @@ -60,6 +61,33 @@ bool ZigbeeHardwareResourceImplementation::enabled() const return m_enabled; } + +void ZigbeeHardwareResourceImplementation::registerHandler(ZigbeeHandler *handler, HandlerType type) +{ + qCDebug(dcZigbeeResource()) << "Registering new zigbee handler" << handler->name() << "with type" << type; + m_handlers.insert(type, handler); +} + +ZigbeeNode *ZigbeeHardwareResourceImplementation::getNode(const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) +{ + ZigbeeNetwork *network = m_zigbeeManager->zigbeeNetworks().value(networkUuid); + if (!network) { + qCWarning(dcZigbeeResource()) << "Network" << networkUuid << "not found."; + return nullptr; + } + return network->getZigbeeNode(extendedAddress); +} + +ZigbeeNetwork::State ZigbeeHardwareResourceImplementation::networkState(const QUuid &networkUuid) +{ + ZigbeeNetwork *network = m_zigbeeManager->zigbeeNetworks().value(networkUuid); + if (!network) { + qCWarning(dcZigbeeResource()) << "Network" << networkUuid << "not found."; + return ZigbeeNetwork::StateUninitialized; + } + return network->state(); +} + void ZigbeeHardwareResourceImplementation::setEnabled(bool enabled) { qCDebug(dcZigbeeResource()) << "Set" << (enabled ? "enabled" : "disabled"); @@ -116,6 +144,18 @@ void ZigbeeHardwareResourceImplementation::onZigbeeAvailableChanged(bool availab void ZigbeeHardwareResourceImplementation::onZigbeeNodeAdded(const QUuid &networkUuid, ZigbeeNode *node) { qCDebug(dcZigbeeResource()) << node << "joined the network" << m_zigbeeManager->zigbeeNetworks().value(networkUuid); + ZigbeeHandler *handler = nullptr; + foreach (ZigbeeHandler *tmp, m_handlers) { + if (tmp->handleNode(node, networkUuid)) { + handler = tmp; + qCDebug(dcZigbeeResource()) << "Node" << node << "taken by handler" << handler->name(); + break; + } + } + if (!handler) { + qCWarning(dcZigbeeResource()) << "No zigbee handler available to handle node" << node; + return; + } } void ZigbeeHardwareResourceImplementation::onZigbeeNodeRemoved(const QUuid &networkUuid, ZigbeeNode *node) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h index 480826cb..1d3afb72 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h @@ -34,7 +34,7 @@ #include #include "zigbee/zigbeemanager.h" -#include "hardware/zigbee/zigbeehardwarereource.h" +#include "hardware/zigbee/zigbeehardwareresource.h" namespace nymeaserver { @@ -48,23 +48,30 @@ public: bool available() const override; bool enabled() const override; -private: - bool m_available = false; - bool m_enabled = false; - ZigbeeManager *m_zigbeeManager = nullptr; + void registerHandler(ZigbeeHandler *handler, HandlerType type = HandlerTypeVendor) override; -protected: - void setEnabled(bool enabled) override; + ZigbeeNode* getNode(const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) override; + ZigbeeNetwork::State networkState(const QUuid &networkUuid) override; public slots: bool enable(); bool disable(); +protected: + void setEnabled(bool enabled) override; + private slots: void onZigbeeAvailableChanged(bool available); void onZigbeeNodeAdded(const QUuid &networkUuid, ZigbeeNode *node); void onZigbeeNodeRemoved(const QUuid &networkUuid, ZigbeeNode *node); +private: + bool m_available = false; + bool m_enabled = false; + ZigbeeManager *m_zigbeeManager = nullptr; + + QMultiMap m_handlers; + }; } diff --git a/libnymea/hardware/zigbee/zigbeehandler.cpp b/libnymea/hardware/zigbee/zigbeehandler.cpp new file mode 100644 index 00000000..a11a697d --- /dev/null +++ b/libnymea/hardware/zigbee/zigbeehandler.cpp @@ -0,0 +1,6 @@ +#include "zigbeehandler.h" + +ZigbeeHandler::ZigbeeHandler() +{ + +} diff --git a/libnymea/hardware/zigbee/zigbeehandler.h b/libnymea/hardware/zigbee/zigbeehandler.h new file mode 100644 index 00000000..f346e6ad --- /dev/null +++ b/libnymea/hardware/zigbee/zigbeehandler.h @@ -0,0 +1,16 @@ +#ifndef ZIGBEEHANDLER_H +#define ZIGBEEHANDLER_H + +#include "zigbeenode.h" + +class ZigbeeHandler +{ +public: + ZigbeeHandler(); + virtual ~ZigbeeHandler() = default; + + virtual QString name() const = 0; + virtual bool handleNode(ZigbeeNode *node, const QUuid &networkUuid) = 0; +}; + +#endif // ZIGBEEHANDLER_H diff --git a/libnymea/hardware/zigbee/zigbeehardwarereource.cpp b/libnymea/hardware/zigbee/zigbeehardwareresource.cpp similarity index 97% rename from libnymea/hardware/zigbee/zigbeehardwarereource.cpp rename to libnymea/hardware/zigbee/zigbeehardwareresource.cpp index c1e5bfd4..4ca1fea0 100644 --- a/libnymea/hardware/zigbee/zigbeehardwarereource.cpp +++ b/libnymea/hardware/zigbee/zigbeehardwareresource.cpp @@ -28,7 +28,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "zigbeehardwarereource.h" +#include "zigbeehardwareresource.h" ZigbeeHardwareResource::ZigbeeHardwareResource(QObject *parent) : HardwareResource("Zigbee hardware resource", parent) diff --git a/libnymea/hardware/zigbee/zigbeehardwarereource.h b/libnymea/hardware/zigbee/zigbeehardwareresource.h similarity index 74% rename from libnymea/hardware/zigbee/zigbeehardwarereource.h rename to libnymea/hardware/zigbee/zigbeehardwareresource.h index f97fcb56..157bf408 100644 --- a/libnymea/hardware/zigbee/zigbeehardwarereource.h +++ b/libnymea/hardware/zigbee/zigbeehardwareresource.h @@ -35,14 +35,32 @@ #include "hardwareresource.h" +#include +#include + +class ZigbeeHandler; +class ZigbeeNode; + class ZigbeeHardwareResource : public HardwareResource { Q_OBJECT public: + enum HandlerType { + HandlerTypeBranding, + HandlerTypeVendor, + HandlerTypeCatchAll + }; + Q_ENUM(HandlerType) explicit ZigbeeHardwareResource(QObject *parent = nullptr); virtual ~ZigbeeHardwareResource() = default; + virtual void registerHandler(ZigbeeHandler *handler, HandlerType type = HandlerTypeVendor) = 0; + virtual ZigbeeNode* getNode(const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) = 0; + virtual ZigbeeNetwork::State networkState(const QUuid &networkUuid) = 0; + +signals: + void networkStateChanged(const QUuid &networkUuid, ZigbeeNetwork::State state); }; diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index a5fb1ba4..39b8db54 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -10,7 +10,8 @@ DEFINES += LIBNYMEA_LIBRARY QMAKE_LFLAGS += -fPIC HEADERS += \ - hardware/zigbee/zigbeehardwarereource.h \ + hardware/zigbee/zigbeehandler.h \ + hardware/zigbee/zigbeehardwareresource.h \ integrations/browseractioninfo.h \ integrations/browseritemactioninfo.h \ integrations/browseritemresult.h \ @@ -103,7 +104,8 @@ HEADERS += \ experiences/experienceplugin.h \ SOURCES += \ - hardware/zigbee/zigbeehardwarereource.cpp \ + hardware/zigbee/zigbeehandler.cpp \ + hardware/zigbee/zigbeehardwareresource.cpp \ integrations/browseractioninfo.cpp \ integrations/browseritemactioninfo.cpp \ integrations/browseritemresult.cpp \ From b1173a3c357882ee58131931ca1910dcb9b6742c Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 7 Nov 2020 00:24:54 +0100 Subject: [PATCH 25/54] Enable missing signal, fix lib exports --- libnymea-core/zigbee/zigbeemanager.cpp | 2 +- libnymea/hardware/zigbee/zigbeehandler.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index ae5337c0..ae6f5910 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -362,7 +362,7 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); nodeInitializer->initializeNode(node); - //emit nodeAdded(network->networkUuid(), node); + emit nodeAdded(network->networkUuid(), node); }); connect(network, &ZigbeeNetwork::nodeRemoved, this, [this, network](ZigbeeNode *node){ diff --git a/libnymea/hardware/zigbee/zigbeehandler.h b/libnymea/hardware/zigbee/zigbeehandler.h index f346e6ad..6bf7e019 100644 --- a/libnymea/hardware/zigbee/zigbeehandler.h +++ b/libnymea/hardware/zigbee/zigbeehandler.h @@ -2,8 +2,9 @@ #define ZIGBEEHANDLER_H #include "zigbeenode.h" +#include "libnymea.h" -class ZigbeeHandler +class LIBNYMEA_EXPORT ZigbeeHandler { public: ZigbeeHandler(); From 4b493ac51d4a64bd6c838446827a920e9a382948 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 12 Nov 2020 11:27:31 +0100 Subject: [PATCH 26/54] provisoric handling for node removal --- .../hardware/zigbee/zigbeehardwareresourceimplementation.cpp | 5 +++++ libnymea/hardware/zigbee/zigbeehandler.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index cab84283..a6f9dcb0 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -161,6 +161,11 @@ void ZigbeeHardwareResourceImplementation::onZigbeeNodeAdded(const QUuid &networ void ZigbeeHardwareResourceImplementation::onZigbeeNodeRemoved(const QUuid &networkUuid, ZigbeeNode *node) { qCDebug(dcZigbeeResource()) << node << "left the network" << m_zigbeeManager->zigbeeNetworks().value(networkUuid); + + foreach (ZigbeeHandler *tmp, m_handlers) { + tmp->handleRemoveNode(node, networkUuid); + } + } } diff --git a/libnymea/hardware/zigbee/zigbeehandler.h b/libnymea/hardware/zigbee/zigbeehandler.h index 6bf7e019..dba0d794 100644 --- a/libnymea/hardware/zigbee/zigbeehandler.h +++ b/libnymea/hardware/zigbee/zigbeehandler.h @@ -4,7 +4,7 @@ #include "zigbeenode.h" #include "libnymea.h" -class LIBNYMEA_EXPORT ZigbeeHandler +class LIBNYMEA_EXPORT ZigbeeHandler { public: ZigbeeHandler(); @@ -12,6 +12,7 @@ public: virtual QString name() const = 0; virtual bool handleNode(ZigbeeNode *node, const QUuid &networkUuid) = 0; + virtual void handleRemoveNode(ZigbeeNode *node, const QUuid &networkUuid) = 0; }; #endif // ZIGBEEHANDLER_H From a3ba16d1111a5fe43fae48bde77224b77e41450e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 12 Nov 2020 11:33:06 +0100 Subject: [PATCH 27/54] Add node debugging and load network before starting it in any case --- libnymea-core/zigbee/zigbeemanager.cpp | 67 +++++++++++++++++-- .../zigbee/zigbeenodeinitializer.cpp | 67 ++++++++++++++----- 2 files changed, 112 insertions(+), 22 deletions(-) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index ae5337c0..c53fdd20 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -272,8 +272,13 @@ void ZigbeeManager::loadZigbeeNetworks() network->setChannel(channel); network->setChannelMask(channelMask); network->setSecurityConfiguration(securityConfiguration); - addNetwork(network); settings.endGroup(); // networkUuid + + // Load the nodes before adding the network internally, so the loaded nodes will not generate added signals + network->loadNetwork(); + + // Add the network internally + addNetwork(network); } settings.endGroup(); // ZigbeeNetworks @@ -359,10 +364,36 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) return; } - ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); - nodeInitializer->initializeNode(node); + qCDebug(dcZigbee()) << "-->" << node; + foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { + qCDebug(dcZigbee()) << " " << endpoint; + if (!endpoint->manufacturerName().isEmpty()) { + qCDebug(dcZigbee()) << " Manufacturer" << endpoint->manufacturerName(); + qCDebug(dcZigbee()) << " Model" << endpoint->modelIdentifier(); + qCDebug(dcZigbee()) << " Version" << endpoint->softwareBuildId(); + } + qCDebug(dcZigbee()) << " Input clusters (" << endpoint->inputClusters().count() << ")"; + foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { + qCDebug(dcZigbee()) << " -" << cluster; + foreach(const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + qCDebug(dcZigbee()) << " - " << attribute; + } + } - //emit nodeAdded(network->networkUuid(), node); + qCDebug(dcZigbee()) << " Output clusters (" << endpoint->outputClusters().count() << ")"; + foreach (ZigbeeCluster *cluster, endpoint->outputClusters()) { + qCDebug(dcZigbee()) << " -" << cluster; + foreach(const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + qCDebug(dcZigbee()) << " - " << attribute; + } + } + } + + +// ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); +// nodeInitializer->initializeNode(node); + // TODO: emit node added once initialized so the plugins can use it + emit nodeAdded(network->networkUuid(), node); }); connect(network, &ZigbeeNetwork::nodeRemoved, this, [this, network](ZigbeeNode *node){ @@ -389,6 +420,34 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) emit nodeAdded(network->networkUuid(), node); }); + qCDebug(dcZigbee()) << "Network added" << network; + foreach (ZigbeeNode *node, network->nodes()) { + qCDebug(dcZigbee()) << "-->" << node; + foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { + qCDebug(dcZigbee()) << " " << endpoint; + if (!endpoint->manufacturerName().isEmpty()) { + qCDebug(dcZigbee()) << " Manufacturer" << endpoint->manufacturerName(); + qCDebug(dcZigbee()) << " Model" << endpoint->modelIdentifier(); + qCDebug(dcZigbee()) << " Version" << endpoint->softwareBuildId(); + } + qCDebug(dcZigbee()) << " Input clusters (" << endpoint->inputClusters().count() << ")"; + foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { + qCDebug(dcZigbee()) << " -" << cluster; + foreach(const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + qCDebug(dcZigbee()) << " - " << attribute; + } + } + + qCDebug(dcZigbee()) << " Output clusters (" << endpoint->outputClusters().count() << ")"; + foreach (ZigbeeCluster *cluster, endpoint->outputClusters()) { + qCDebug(dcZigbee()) << " -" << cluster; + foreach(const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + qCDebug(dcZigbee()) << " - " << attribute; + } + } + } + } + m_zigbeeNodeInitializers.insert(network->networkUuid(), nodeInitializer); } diff --git a/libnymea-core/zigbee/zigbeenodeinitializer.cpp b/libnymea-core/zigbee/zigbeenodeinitializer.cpp index 96b48cfe..68c21891 100644 --- a/libnymea-core/zigbee/zigbeenodeinitializer.cpp +++ b/libnymea-core/zigbee/zigbeenodeinitializer.cpp @@ -48,35 +48,66 @@ void ZigbeeNodeInitializer::initializeNode(ZigbeeNode *node) // Initialize and configure server clusters foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { - - // Read values + // Configure attribute reporting if (endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { - } - - foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { - switch (cluster->clusterId()) { - case ZigbeeClusterLibrary::ClusterIdPowerConfiguration: { - // Read values + // Read current battery remaining + ZigbeeClusterReply *readAttributeReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining}); + connect(readAttributeReply, &ZigbeeClusterReply::finished, this, [this, node, readAttributeReply](){ + if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to read power cluster attributes" << readAttributeReply->error(); + emit nodeInitialized(node); + return; + } + }); + // Configure attribute rporting for battery remaining + ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; + reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; + reportingConfig.dataType = Zigbee::Uint8; + reportingConfig.minReportingInterval = 300; + reportingConfig.maxReportingInterval = 2700; + reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); - // Configure attribute reporting - - break; - } - default: - // Not handeld, leave it to the plugin - break; - } - + ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); + connect(reportingReply, &ZigbeeClusterReply::finished, this, [reportingReply](){ + if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to read power cluster attributes" << reportingReply->error(); + return; + } + qCDebug(dcZigbee()) << "Reporting config finished" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); + }); } } // Initialize and configure client clusters + foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { + if (endpoint->hasOutputCluster(ZigbeeClusterLibrary::ClusterIdOnOff)) { + // Bind command + ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, m_network->coordinatorNode()->extendedAddress(), 0x01); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [zdoReply](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to bind OnOff cluster attributes" << zdoReply->error(); + return; + } + }); + } - + if (endpoint->hasOutputCluster(ZigbeeClusterLibrary::ClusterIdLevelControl)) { + // Bind command + ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, m_network->coordinatorNode()->extendedAddress(), 0x01); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [this, node, zdoReply](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to bind Level cluster attributes" << zdoReply->error(); + emit nodeInitialized(node); + return; + } + emit nodeInitialized(node); + }); + } + } } From e9b5b618b2cbf6a22edb4ee3f15d30541b0639d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 12 Nov 2020 13:26:55 +0100 Subject: [PATCH 28/54] Implement remove node into the resource and missing network state changed signal handling --- .../zigbeehardwareresourceimplementation.cpp | 17 +++++++++++++++++ .../zigbeehardwareresourceimplementation.h | 3 +++ .../hardware/zigbee/zigbeehardwareresource.h | 1 + 3 files changed, 21 insertions(+) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index a6f9dcb0..09cddf8e 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -46,6 +46,7 @@ ZigbeeHardwareResourceImplementation::ZigbeeHardwareResourceImplementation(Zigbe ZigbeeHardwareResource(parent), m_zigbeeManager(zigbeeManager) { + connect(m_zigbeeManager, &ZigbeeManager::zigbeeNetworkChanged, this, &ZigbeeHardwareResourceImplementation::onZigbeeNetworkChanged); connect(m_zigbeeManager, &ZigbeeManager::nodeAdded, this, &ZigbeeHardwareResourceImplementation::onZigbeeNodeAdded); connect(m_zigbeeManager, &ZigbeeManager::nodeRemoved, this, &ZigbeeHardwareResourceImplementation::onZigbeeNodeRemoved); connect(m_zigbeeManager, &ZigbeeManager::availableChanged, this, &ZigbeeHardwareResourceImplementation::onZigbeeAvailableChanged); @@ -78,6 +79,17 @@ ZigbeeNode *ZigbeeHardwareResourceImplementation::getNode(const QUuid &networkUu return network->getZigbeeNode(extendedAddress); } +void ZigbeeHardwareResourceImplementation::removeNodeFromNetwork(const QUuid &networkUuid, ZigbeeNode *node) +{ + ZigbeeNetwork *network = m_zigbeeManager->zigbeeNetworks().value(networkUuid); + if (!network) { + qCWarning(dcZigbeeResource()) << "Can not remove note from network" << networkUuid << "because there is no network with this uuid."; + return; + } + + network->removeZigbeeNode(node->extendedAddress()); +} + ZigbeeNetwork::State ZigbeeHardwareResourceImplementation::networkState(const QUuid &networkUuid) { ZigbeeNetwork *network = m_zigbeeManager->zigbeeNetworks().value(networkUuid); @@ -141,6 +153,11 @@ void ZigbeeHardwareResourceImplementation::onZigbeeAvailableChanged(bool availab emit availableChanged(available); } +void ZigbeeHardwareResourceImplementation::onZigbeeNetworkChanged(ZigbeeNetwork *network) +{ + emit networkStateChanged(network->networkUuid(), network->state()); +} + void ZigbeeHardwareResourceImplementation::onZigbeeNodeAdded(const QUuid &networkUuid, ZigbeeNode *node) { qCDebug(dcZigbeeResource()) << node << "joined the network" << m_zigbeeManager->zigbeeNetworks().value(networkUuid); diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h index 1d3afb72..fa84f6a0 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h @@ -51,6 +51,8 @@ public: void registerHandler(ZigbeeHandler *handler, HandlerType type = HandlerTypeVendor) override; ZigbeeNode* getNode(const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) override; + void removeNodeFromNetwork(const QUuid &networkUuid, ZigbeeNode *node) override; + ZigbeeNetwork::State networkState(const QUuid &networkUuid) override; public slots: @@ -62,6 +64,7 @@ protected: private slots: void onZigbeeAvailableChanged(bool available); + void onZigbeeNetworkChanged(ZigbeeNetwork *network); void onZigbeeNodeAdded(const QUuid &networkUuid, ZigbeeNode *node); void onZigbeeNodeRemoved(const QUuid &networkUuid, ZigbeeNode *node); diff --git a/libnymea/hardware/zigbee/zigbeehardwareresource.h b/libnymea/hardware/zigbee/zigbeehardwareresource.h index 157bf408..dcbe5e6a 100644 --- a/libnymea/hardware/zigbee/zigbeehardwareresource.h +++ b/libnymea/hardware/zigbee/zigbeehardwareresource.h @@ -56,6 +56,7 @@ public: virtual void registerHandler(ZigbeeHandler *handler, HandlerType type = HandlerTypeVendor) = 0; virtual ZigbeeNode* getNode(const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) = 0; + virtual void removeNodeFromNetwork(const QUuid &networkUuid, ZigbeeNode *node) = 0; virtual ZigbeeNetwork::State networkState(const QUuid &networkUuid) = 0; From 18d607319e997660a9cf8d7a03492fcd0f085581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 12 Nov 2020 17:48:53 +0100 Subject: [PATCH 29/54] Ping rx on when idle devices after network running --- libnymea-core/zigbee/zigbeemanager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index d3345421..9517c26f 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -313,6 +313,16 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) connect(network, &ZigbeeNetwork::stateChanged, this, [this, network](ZigbeeNetwork::State state){ Q_UNUSED(state) qCDebug(dcZigbee()) << "Network state changed" << network; + if (state == ZigbeeNetwork::StateRunning) { + + // Send a broadcast request to all powered nodes + foreach (ZigbeeNode *node, network->nodes()) { + if (node->macCapabilities().receiverOnWhenIdle && node->shortAddress() != 0x0000) { + node->deviceObject()->requestMgmtLqi(); + } + } + } + evaluateZigbeeAvailable(); emit zigbeeNetworkChanged(network); }); From 16bc4684e100c64a56a745061837d5a8b88abb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Nov 2020 07:55:33 +0100 Subject: [PATCH 30/54] Experiment with binding and attribute report configuration --- libnymea-core/zigbee/zigbeemanager.cpp | 6 +- .../zigbee/zigbeenodeinitializer.cpp | 55 ++++++++++++------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 9517c26f..f45e7225 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -400,9 +400,9 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) } -// ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); -// nodeInitializer->initializeNode(node); - // TODO: emit node added once initialized so the plugins can use it + ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); + nodeInitializer->initializeNode(node); + //TODO: emit node added once initialized so the plugins can use it emit nodeAdded(network->networkUuid(), node); }); diff --git a/libnymea-core/zigbee/zigbeenodeinitializer.cpp b/libnymea-core/zigbee/zigbeenodeinitializer.cpp index 68c21891..148c54b9 100644 --- a/libnymea-core/zigbee/zigbeenodeinitializer.cpp +++ b/libnymea-core/zigbee/zigbeenodeinitializer.cpp @@ -39,6 +39,7 @@ ZigbeeNodeInitializer::ZigbeeNodeInitializer(ZigbeeNetwork *network, QObject *pa QObject(parent), m_network(network) { + // Bind the coordinator to group 0x0000 } @@ -46,38 +47,54 @@ void ZigbeeNodeInitializer::initializeNode(ZigbeeNode *node) { qCDebug(dcZigbee()) << "Start initializing node internally" << node; + m_network->coordinatorNode()->deviceObject()->requestBindShortAddress(0x01, ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000); + + // Initialize and configure server clusters foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { // Configure attribute reporting if (endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { // Read current battery remaining + qCDebug(dcZigbee()) << "Read power configuration cluster attributes" << node; ZigbeeClusterReply *readAttributeReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining}); - connect(readAttributeReply, &ZigbeeClusterReply::finished, this, [this, node, readAttributeReply](){ + connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){ if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) { qCWarning(dcZigbee()) << "Failed to read power cluster attributes" << readAttributeReply->error(); - emit nodeInitialized(node); + //emit nodeInitialized(node); return; } - }); + qCDebug(dcZigbee()) << "Read power configuration cluster attributes finished successfully"; + // Bind the cluster to the coordinator + qCDebug(dcZigbee()) << "Bind power configuration cluster to coordinaotr"; + ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, m_network->coordinatorNode()->extendedAddress(), 0x01); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to bind power cluster to coordinator" << readAttributeReply->error(); + return; + } + qCDebug(dcZigbee()) << "Bind power configuration cluster to coordinaotr finished successfully"; - // Configure attribute rporting for battery remaining - ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; - reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; - reportingConfig.dataType = Zigbee::Uint8; - reportingConfig.minReportingInterval = 300; - reportingConfig.maxReportingInterval = 2700; - reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); + // Configure attribute rporting for battery remaining + ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; + reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; + reportingConfig.dataType = Zigbee::Uint8; + reportingConfig.minReportingInterval = 300; + reportingConfig.maxReportingInterval = 2700; + reportingConfig.reportableChange = ZigbeeDataType(static_cast(14)).data(); - ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); - connect(reportingReply, &ZigbeeClusterReply::finished, this, [reportingReply](){ - if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { - qCWarning(dcZigbee()) << "Failed to read power cluster attributes" << reportingReply->error(); - return; - } + qCDebug(dcZigbee()) << "Configure attribute reporting for power configuration cluster to coordinator"; + ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); + connect(reportingReply, &ZigbeeClusterReply::finished, this, [reportingReply](){ + if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to read power cluster attributes" << reportingReply->error(); + return; + } - qCDebug(dcZigbee()) << "Reporting config finished" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); + qCDebug(dcZigbee()) << "Reporting config finished" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); + }); + }); }); } } @@ -88,7 +105,7 @@ void ZigbeeNodeInitializer::initializeNode(ZigbeeNode *node) if (endpoint->hasOutputCluster(ZigbeeClusterLibrary::ClusterIdOnOff)) { // Bind command - ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, m_network->coordinatorNode()->extendedAddress(), 0x01); + ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, m_network->coordinatorNode()->shortAddress()); connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [zdoReply](){ if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { qCWarning(dcZigbee()) << "Failed to bind OnOff cluster attributes" << zdoReply->error(); @@ -99,7 +116,7 @@ void ZigbeeNodeInitializer::initializeNode(ZigbeeNode *node) if (endpoint->hasOutputCluster(ZigbeeClusterLibrary::ClusterIdLevelControl)) { // Bind command - ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, m_network->coordinatorNode()->extendedAddress(), 0x01); + ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, m_network->coordinatorNode()->shortAddress()); connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [this, node, zdoReply](){ if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { qCWarning(dcZigbee()) << "Failed to bind Level cluster attributes" << zdoReply->error(); From ab9a497df8eebc0e700cd9ee93e496add1d1d085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Nov 2020 10:20:58 +0100 Subject: [PATCH 31/54] Bump api version containing new Zigbee namespace --- .../zigbee/zigbeenodeinitializer.cpp | 5 +- tests/auto/api.json | 137 ++++++++++++++++++ 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/libnymea-core/zigbee/zigbeenodeinitializer.cpp b/libnymea-core/zigbee/zigbeenodeinitializer.cpp index 148c54b9..b4c005ad 100644 --- a/libnymea-core/zigbee/zigbeenodeinitializer.cpp +++ b/libnymea-core/zigbee/zigbeenodeinitializer.cpp @@ -39,7 +39,6 @@ ZigbeeNodeInitializer::ZigbeeNodeInitializer(ZigbeeNetwork *network, QObject *pa QObject(parent), m_network(network) { - // Bind the coordinator to group 0x0000 } @@ -47,8 +46,8 @@ void ZigbeeNodeInitializer::initializeNode(ZigbeeNode *node) { qCDebug(dcZigbee()) << "Start initializing node internally" << node; - m_network->coordinatorNode()->deviceObject()->requestBindShortAddress(0x01, ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000); - + // Bind the coordinator to group 0x0000 + //m_network->coordinatorNode()->deviceObject()->requestBindShortAddress(0x01, ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000); // Initialize and configure server clusters foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { diff --git a/tests/auto/api.json b/tests/auto/api.json index 1a25139c..bc1f2f20 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -364,6 +364,25 @@ "WirelessModeAdhoc", "WirelessModeInfrastructure", "WirelessModeAccessPoint" + ], + "ZigbeeBackendType": [ + "ZigbeeBackendTypeDeconz", + "ZigbeeBackendTypeNxp" + ], + "ZigbeeError": [ + "ZigbeeErrorNoError", + "ZigbeeErrorAdapterNotAvailable", + "ZigbeeErrorAdapterAlreadyInUse", + "ZigbeeErrorNetworkUuidNotFound", + "ZigbeeErrorDurationOutOfRange", + "ZigbeeErrorNetworkOffline" + ], + "ZigbeeNetworkState": [ + "ZigbeeNetworkStateOffline", + "ZigbeeNetworkStateStarting", + "ZigbeeNetworkStateUpdating", + "ZigbeeNetworkStateOnline", + "ZigbeeNetworkStateError" ] }, "flags": { @@ -1932,6 +1951,66 @@ "success": "Bool", "transactionId": "Int" } + }, + "Zigbee.AddNetwork": { + "description": "Create a new Zigbee network for the given serialPort, baud rate and backend type. Get those information from the available Zigbee adapters.The channel mask is optional and defaults to all channels [11, 26]. The quietest channel from the given channel mask will be picked during network creation. The channel mask is a uint32 flag and the the bit number represents the channel which should enabled for scanning. All channels would be the value 0x07fff800.", + "params": { + "backendType": "$ref:ZigbeeBackendType", + "baudRate": "Uint", + "o:channelMask": "Uint", + "serialPort": "String" + }, + "returns": { + "o:networkUuid": "Uuid", + "zigbeeError": "$ref:ZigbeeError" + } + }, + "Zigbee.FactoryResetNetwork": { + "description": "Factory reset the network with the given networkUuid. The network does not have to be Online for this procedure, and all associated nodes and things will be removed permanently. Make sure the user realy wants to do this because this can not be undone.", + "params": { + "networkUuid": "Uuid" + }, + "returns": { + "zigbeeError": "$ref:ZigbeeError" + } + }, + "Zigbee.GetAdapters": { + "description": "Get the list of available Zigbee adapter candidates in order to set up the zigbee network on the desired serial interface. The serialPort property can be used as unique identifier. If an adapter hardware has been recognized as a supported hardware, the 'hardwareRecognized' property will be true and the baud rate and backend configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually.", + "params": { + }, + "returns": { + "adapters": "$ref:ZigbeeAdapters" + } + }, + "Zigbee.GetNetworks": { + "description": "Returns the list of zigbee networks configured in the system.", + "params": { + }, + "returns": { + "zigbeeNetworks": [ + "$ref:ZigbeeNetwork" + ] + } + }, + "Zigbee.RemoveNetwork": { + "description": "Remove the zigbee network with the given network uuid.", + "params": { + "networkUuid": "Uuid" + }, + "returns": { + "zigbeeError": "$ref:ZigbeeError" + } + }, + "Zigbee.SetPermitJoin": { + "description": "Allow or deny nodes to join the network with the given networkUuid for a specific duration in seconds. The duration values has to be between 0 and 255 seconds. The permitJoinDuration indicates how long permit has been enabled and the permitJoinDuration indicates the rest of the time. Those values can be used to show a countdown or progressbar. This method can be recalled for resetting the timeout. If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. The shortAddress is optional and defaults to the broadcast address (0xfffc) for all routers in the network. If the short address matches the address of a router node in the network, only that router will be able to allow new nodes to join the network. A new node will join to the router with the best link quality index (LQI).", + "params": { + "duration": "Uint", + "networkUuid": "Uuid", + "o:shortAddress": "Uint" + }, + "returns": { + "zigbeeError": "$ref:ZigbeeError" + } } }, "notifications": { @@ -2350,6 +2429,36 @@ "success": "Bool", "transactionId": "Int" } + }, + "Zigbee.AdapterAdded": { + "description": "Emitted whenever a new Zigbee adapter candidate has been detected in the system.", + "params": { + "adapter": "$ref:ZigbeeAdapter" + } + }, + "Zigbee.AdapterRemoved": { + "description": "Emitted whenever a Zigbee adapter has been removed from the system (i.e. unplugged).", + "params": { + "adapter": "$ref:ZigbeeAdapter" + } + }, + "Zigbee.NetworkAdded": { + "description": "Emitted whenever a new Zigbee network has been added.", + "params": { + "zigbeeNetwork": "$ref:ZigbeeNetwork" + } + }, + "Zigbee.NetworkChanged": { + "description": "Emitted whenever a new Zigbee network has changed.", + "params": { + "zigbeeNetwork": "$ref:ZigbeeNetwork" + } + }, + "Zigbee.NetworkRemoved": { + "description": "Emitted whenever a new Zigbee network has been removed.", + "params": { + "networkUuid": "Uuid" + } } }, "types": { @@ -2819,6 +2928,34 @@ "r:mode": "$ref:WirelessMode", "r:o:currentAccessPoint": "$ref:WirelessAccessPoint", "r:state": "$ref:NetworkDeviceState" + }, + "ZigbeeAdapter": { + "backendType": "$ref:ZigbeeBackendType", + "baudRate": "Int", + "description": "String", + "hardwareRecognized": "Bool", + "name": "String", + "serialNumber": "String", + "serialPort": "String" + }, + "ZigbeeAdapters": [ + "$ref:ZigbeeAdapter" + ], + "ZigbeeNetwork": { + "backendType": "$ref:ZigbeeBackendType", + "baudRate": "Uint", + "channel": "Uint", + "channelMask": "Uint", + "enabled": "Bool", + "firmwareVersion": "String", + "macAddress": "String", + "networkState": "$ref:ZigbeeNetworkState", + "networkUuid": "Uuid", + "panId": "Uint", + "permitJoiningDuration": "Uint", + "permitJoiningEnabled": "Bool", + "permitJoiningRemaining": "Uint", + "serialPort": "String" } } } From 562e3235d848b1b3f52c85eee41207aef8a8da24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Nov 2020 10:51:31 +0100 Subject: [PATCH 32/54] Add nymea-zigbee as build dependency to libnymea --- libnymea/libnymea.pro | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index 39b8db54..6be24a33 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -7,6 +7,9 @@ QT += network bluetooth dbus QT -= gui DEFINES += LIBNYMEA_LIBRARY +CONFIG += link_pkgconfig +PKGCONFIG += nymea-zigbee + QMAKE_LFLAGS += -fPIC HEADERS += \ From 400239fc6c3ad39c017bcc61f7dde4c0e297d495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Nov 2020 11:07:01 +0100 Subject: [PATCH 33/54] Add libnymea-zigbee-dev package to the build dependencies --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 5f96866a..d1df3fd3 100644 --- a/debian/control +++ b/debian/control @@ -12,6 +12,7 @@ Build-Depends: debhelper (>= 9.0.0), libnymea-mqtt-dev (>= 0.1.2), libnymea-networkmanager-dev (>= 0.4.0), libnymea-remoteproxyclient-dev, + libnymea-zigbee-dev, libpython3-dev, libqt5websockets5-dev, libqt5bluetooth5, From 3ae8baaa40900c0168691832db6714ee9ae2808f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Nov 2020 12:50:56 +0100 Subject: [PATCH 34/54] Remove serialport module since not required any more in nymea --- libnymea-core/libnymea-core.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 4017be9b..18b88770 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -4,7 +4,7 @@ TARGET = nymea-core include(../nymea.pri) -QT += sql qml serialport +QT += sql qml INCLUDEPATH += $$top_srcdir/libnymea $$top_builddir LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto From 255a6dc09076a1c80d88e7bcb711020f0a0c39b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Nov 2020 14:50:16 +0100 Subject: [PATCH 35/54] Move zigbeemanager include into the cpp --- libnymea-core/nymeacore.cpp | 2 ++ libnymea-core/nymeacore.h | 2 -- libnymea-core/zigbee/zigbeemanager.cpp | 4 ++-- libnymea-core/zigbee/zigbeenodeinitializer.cpp | 5 +++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index f2fc3e58..bf3be374 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -51,6 +51,8 @@ #include "cloud/cloudnotifications.h" #include "cloud/cloudtransport.h" +#include "zigbee/zigbeemanager.h" + #include #include diff --git a/libnymea-core/nymeacore.h b/libnymea-core/nymeacore.h index 364de311..69902b68 100644 --- a/libnymea-core/nymeacore.h +++ b/libnymea-core/nymeacore.h @@ -46,8 +46,6 @@ #include "time/timemanager.h" #include "hardwaremanagerimplementation.h" -#include "zigbee/zigbeemanager.h" - #include "debugserverhandler.h" #include diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index f45e7225..faa8b2aa 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -400,8 +400,8 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) } - ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); - nodeInitializer->initializeNode(node); +// ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); +// nodeInitializer->initializeNode(node); //TODO: emit node added once initialized so the plugins can use it emit nodeAdded(network->networkUuid(), node); diff --git a/libnymea-core/zigbee/zigbeenodeinitializer.cpp b/libnymea-core/zigbee/zigbeenodeinitializer.cpp index b4c005ad..b7a5c6de 100644 --- a/libnymea-core/zigbee/zigbeenodeinitializer.cpp +++ b/libnymea-core/zigbee/zigbeenodeinitializer.cpp @@ -119,11 +119,12 @@ void ZigbeeNodeInitializer::initializeNode(ZigbeeNode *node) connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [this, node, zdoReply](){ if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { qCWarning(dcZigbee()) << "Failed to bind Level cluster attributes" << zdoReply->error(); - emit nodeInitialized(node); + //emit nodeInitialized(node); return; } - emit nodeInitialized(node); }); } } + + //emit nodeInitialized(node); } From 7ab98f65f7cd5f95655f86eeba52b51ec42a924d Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 16 Nov 2020 15:14:17 +0100 Subject: [PATCH 36/54] Improve the plugin <-> node matching mechanism * A ZigbeeNode can now only be claimed by 1 plugin. * Unhandled nodes will now be re-evaluated on restart as there might have been new plugins installed which could handle this node now. --- .../zigbeehardwareresourceimplementation.cpp | 59 +++++++++++++++++-- .../zigbeehardwareresourceimplementation.h | 7 ++- .../hardware/zigbee/zigbeehardwareresource.h | 2 +- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index 09cddf8e..46d84594 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -69,14 +69,32 @@ void ZigbeeHardwareResourceImplementation::registerHandler(ZigbeeHandler *handle m_handlers.insert(type, handler); } -ZigbeeNode *ZigbeeHardwareResourceImplementation::getNode(const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) +ZigbeeNode *ZigbeeHardwareResourceImplementation::claimNode(ZigbeeHandler *handler, const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) { + if (!m_handlers.values().contains(handler)) { + qCWarning(dcZigbeeResource()) << "Handler" << handler->name() << "is not registered. Not allowing node to be claimed."; + return nullptr; + } + ZigbeeNetwork *network = m_zigbeeManager->zigbeeNetworks().value(networkUuid); if (!network) { qCWarning(dcZigbeeResource()) << "Network" << networkUuid << "not found."; return nullptr; } - return network->getZigbeeNode(extendedAddress); + + ZigbeeNode *node = network->getZigbeeNode(extendedAddress); + if (!node) { + qCWarning(dcZigbeeResource()) << "Node with address" << extendedAddress << "not found in Zigbee network" << networkUuid.toString(); + return nullptr; + } + + if (m_nodeHandlers.contains(node)) { + qCWarning(dcZigbeeResource()) << "Node with address" << extendedAddress << "is already claimed by another handler (" << m_nodeHandlers.value(node)->name() << "). Not allowing node to be reclaimed."; + return nullptr; + } + + m_nodeHandlers.insert(node, handler); + return node; } void ZigbeeHardwareResourceImplementation::removeNodeFromNetwork(const QUuid &networkUuid, ZigbeeNode *node) @@ -142,6 +160,24 @@ bool ZigbeeHardwareResourceImplementation::disable() return true; } +void ZigbeeHardwareResourceImplementation::thingsLoaded() +{ + m_thingsLoaded = true; + + // We can assume here that all handled nodes have been claimed by plugins + // In case we started up and loaded new zigbee plugins, let's try to get all previously joined nodes handled now... + foreach (ZigbeeNetwork *network, m_zigbeeManager->zigbeeNetworks()) { + if (network->state() == ZigbeeNetwork::StateRunning) { + foreach (ZigbeeNode *node, network->nodes()) { + if (!m_nodeHandlers.contains(node)) { + qCDebug(dcZigbeeResource()) << "Node" << node << "is not yet handled by any plugin. Trying to find a suitable plugin."; + onZigbeeNodeAdded(network->networkUuid(), node); + } + } + } + } +} + void ZigbeeHardwareResourceImplementation::onZigbeeAvailableChanged(bool available) { if (available) { @@ -156,6 +192,18 @@ void ZigbeeHardwareResourceImplementation::onZigbeeAvailableChanged(bool availab void ZigbeeHardwareResourceImplementation::onZigbeeNetworkChanged(ZigbeeNetwork *network) { emit networkStateChanged(network->networkUuid(), network->state()); + + // If the network is now ready and things have been loaded already, check if there are + // unclaimed nodes that might be handled now. This might happen if a node joins the network + // but no appropriate plugin had been installed at the time. If additional plugins have + // been installed now, such nodes might be handled by them now. + if (network->state() == ZigbeeNetwork::StateRunning && m_thingsLoaded) { + foreach (ZigbeeNode *node, network->nodes()) { + if (!m_nodeHandlers.contains(node)) { + onZigbeeNodeAdded(network->networkUuid(), node); + } + } + } } void ZigbeeHardwareResourceImplementation::onZigbeeNodeAdded(const QUuid &networkUuid, ZigbeeNode *node) @@ -165,6 +213,7 @@ void ZigbeeHardwareResourceImplementation::onZigbeeNodeAdded(const QUuid &networ foreach (ZigbeeHandler *tmp, m_handlers) { if (tmp->handleNode(node, networkUuid)) { handler = tmp; + m_nodeHandlers.insert(node, handler); qCDebug(dcZigbeeResource()) << "Node" << node << "taken by handler" << handler->name(); break; } @@ -179,10 +228,10 @@ void ZigbeeHardwareResourceImplementation::onZigbeeNodeRemoved(const QUuid &netw { qCDebug(dcZigbeeResource()) << node << "left the network" << m_zigbeeManager->zigbeeNetworks().value(networkUuid); - foreach (ZigbeeHandler *tmp, m_handlers) { - tmp->handleRemoveNode(node, networkUuid); + ZigbeeHandler *handler = m_nodeHandlers.value(node); + if (handler) { + handler->handleRemoveNode(node, networkUuid); } - } } diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h index fa84f6a0..c01e2b8b 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h @@ -50,7 +50,7 @@ public: void registerHandler(ZigbeeHandler *handler, HandlerType type = HandlerTypeVendor) override; - ZigbeeNode* getNode(const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) override; + ZigbeeNode* claimNode(ZigbeeHandler *handler, const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) override; void removeNodeFromNetwork(const QUuid &networkUuid, ZigbeeNode *node) override; ZigbeeNetwork::State networkState(const QUuid &networkUuid) override; @@ -59,6 +59,8 @@ public slots: bool enable(); bool disable(); + void thingsLoaded(); + protected: void setEnabled(bool enabled) override; @@ -75,6 +77,9 @@ private: QMultiMap m_handlers; + bool m_thingsLoaded = false; + QHash m_nodeHandlers; + }; } diff --git a/libnymea/hardware/zigbee/zigbeehardwareresource.h b/libnymea/hardware/zigbee/zigbeehardwareresource.h index dcbe5e6a..5f8a64a7 100644 --- a/libnymea/hardware/zigbee/zigbeehardwareresource.h +++ b/libnymea/hardware/zigbee/zigbeehardwareresource.h @@ -55,7 +55,7 @@ public: virtual ~ZigbeeHardwareResource() = default; virtual void registerHandler(ZigbeeHandler *handler, HandlerType type = HandlerTypeVendor) = 0; - virtual ZigbeeNode* getNode(const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) = 0; + virtual ZigbeeNode* claimNode(ZigbeeHandler *hanlder, const QUuid &networkUuid, const ZigbeeAddress &extendedAddress) = 0; virtual void removeNodeFromNetwork(const QUuid &networkUuid, ZigbeeNode *node) = 0; virtual ZigbeeNetwork::State networkState(const QUuid &networkUuid) = 0; From 897b49b1f31c10c710ffd1dba9a8c372fc92dde9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Nov 2020 16:07:54 +0100 Subject: [PATCH 37/54] Add zigbee notifications to enable/disable JSONRPC tests --- tests/auto/jsonrpc/testjsonrpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/jsonrpc/testjsonrpc.cpp b/tests/auto/jsonrpc/testjsonrpc.cpp index 7fddb182..b5c33cec 100644 --- a/tests/auto/jsonrpc/testjsonrpc.cpp +++ b/tests/auto/jsonrpc/testjsonrpc.cpp @@ -674,7 +674,7 @@ void TestJSONRPC::enableDisableNotifications_legacy() QStringList expectedNamespaces; if (enabled == "true") { - expectedNamespaces << "Actions" << "NetworkManager" << "Devices" << "Integrations" << "System" << "Rules" << "States" << "Logging" << "Tags" << "JSONRPC" << "Configuration" << "Events" << "Scripts" << "Users"; + expectedNamespaces << "Actions" << "NetworkManager" << "Devices" << "Integrations" << "System" << "Rules" << "States" << "Logging" << "Tags" << "JSONRPC" << "Configuration" << "Events" << "Scripts" << "Users" << "Zigbee"; } std::sort(expectedNamespaces.begin(), expectedNamespaces.end()); From 0c4a23a487806e41347173342e2e70d41037ad8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Nov 2020 16:29:45 +0100 Subject: [PATCH 38/54] Bump JSON ROC API version --- nymea.pro | 2 +- tests/auto/api.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nymea.pro b/nymea.pro index 4a8c3cda..9f9e0cd3 100644 --- a/nymea.pro +++ b/nymea.pro @@ -5,7 +5,7 @@ NYMEA_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p" # define protocol versions JSON_PROTOCOL_VERSION_MAJOR=5 -JSON_PROTOCOL_VERSION_MINOR=2 +JSON_PROTOCOL_VERSION_MINOR=3 JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}" LIBNYMEA_API_VERSION_MAJOR=7 LIBNYMEA_API_VERSION_MINOR=0 diff --git a/tests/auto/api.json b/tests/auto/api.json index bc1f2f20..8669fe75 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,4 +1,4 @@ -5.2 +5.3 { "enums": { "BasicType": [ From 57ec37712a60e69f10137cea3bebcbb48250c888 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 16 Nov 2020 17:58:13 +0100 Subject: [PATCH 39/54] tell the zigbee resource when we're done loading things --- libnymea-core/hardwaremanagerimplementation.cpp | 5 +++++ libnymea-core/hardwaremanagerimplementation.h | 6 +++++- libnymea-core/nymeacore.cpp | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libnymea-core/hardwaremanagerimplementation.cpp b/libnymea-core/hardwaremanagerimplementation.cpp index 0222c86f..8d19558c 100644 --- a/libnymea-core/hardwaremanagerimplementation.cpp +++ b/libnymea-core/hardwaremanagerimplementation.cpp @@ -142,4 +142,9 @@ ZigbeeHardwareResource *HardwareManagerImplementation::zigbeeResource() return m_zigbeeResource; } +void HardwareManagerImplementation::thingsLoaded() +{ + m_zigbeeResource->thingsLoaded(); +} + } diff --git a/libnymea-core/hardwaremanagerimplementation.h b/libnymea-core/hardwaremanagerimplementation.h index 9e807803..8a67e54e 100644 --- a/libnymea-core/hardwaremanagerimplementation.h +++ b/libnymea-core/hardwaremanagerimplementation.h @@ -42,6 +42,7 @@ namespace nymeaserver { class Platform; class MqttBroker; class ZigbeeManager; +class ZigbeeHardwareResourceImplementation; class HardwareManagerImplementation : public HardwareManager { @@ -61,6 +62,9 @@ public: I2CManager *i2cManager() override; ZigbeeHardwareResource *zigbeeResource() override; +public slots: + void thingsLoaded(); + private: QNetworkAccessManager *m_networkAccessManager = nullptr; @@ -74,7 +78,7 @@ private: BluetoothLowEnergyManager *m_bluetoothLowEnergyManager = nullptr; MqttProvider *m_mqttProvider = nullptr; I2CManager *m_i2cManager = nullptr; - ZigbeeHardwareResource *m_zigbeeResource = nullptr; + ZigbeeHardwareResourceImplementation *m_zigbeeResource = nullptr; }; } diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index bf3be374..6bedb8c9 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -824,6 +824,9 @@ void NymeaCore::thingManagerLoaded() // Evaluate rules on current time onDateTimeChanged(m_timeManager->currentDateTime()); + // Tell zigbee we're done with loading stuff... + m_hardwareManager->thingsLoaded(); + emit initialized(); // Do some houskeeping... From bfc44760192832a4997cab1d2c4205c333f9e020 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 16 Nov 2020 22:18:19 +0100 Subject: [PATCH 40/54] allow the same plugin fetching a zigbeenode multiple times inform the zigbeemanager about things finishing loading --- .../hardware/zigbee/zigbeehardwareresourceimplementation.cpp | 4 ++-- libnymea-core/nymeacore.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index 46d84594..a7ef19a8 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -88,12 +88,12 @@ ZigbeeNode *ZigbeeHardwareResourceImplementation::claimNode(ZigbeeHandler *handl return nullptr; } - if (m_nodeHandlers.contains(node)) { + if (m_nodeHandlers.contains(node) && m_nodeHandlers.value(node) != handler) { qCWarning(dcZigbeeResource()) << "Node with address" << extendedAddress << "is already claimed by another handler (" << m_nodeHandlers.value(node)->name() << "). Not allowing node to be reclaimed."; return nullptr; } - m_nodeHandlers.insert(node, handler); + m_nodeHandlers[node] = handler; return node; } diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index 6bedb8c9..35d5f1c3 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -824,7 +824,7 @@ void NymeaCore::thingManagerLoaded() // Evaluate rules on current time onDateTimeChanged(m_timeManager->currentDateTime()); - // Tell zigbee we're done with loading stuff... + // Tell hardare resources we're done with loading stuff... m_hardwareManager->thingsLoaded(); emit initialized(); From 97b1623e2781311ef6f4254528dc3c9f5b973ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 18 Nov 2020 09:52:47 +0100 Subject: [PATCH 41/54] Add platform network creation --- libnymea-core/zigbee/zigbeemanager.cpp | 69 ++++++++++++++++++++++++-- libnymea-core/zigbee/zigbeemanager.h | 4 +- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index faa8b2aa..42c3ac43 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -32,6 +32,9 @@ #include "nymeasettings.h" #include "loggingcategories.h" +#include +#include + #include NYMEA_LOGGING_CATEGORY(dcZigbee, "Zigbee") @@ -82,8 +85,13 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : // Load zigbee networks from settings loadZigbeeNetworks(); - // TODO: load platform configuration for networks we know for sure how they work after loading already configured networks + // Check if we have a zigbee platform configuration and if we have to create the platform network automatically + checkPlatformConfiguration(); + // Start all loaded networks + foreach (ZigbeeNetwork *network, m_zigbeeNetworks.values()) { + network->startNetwork(); + } } bool ZigbeeManager::available() const @@ -106,7 +114,7 @@ QHash ZigbeeManager::zigbeeNetworks() const return m_zigbeeNetworks; } -QPair ZigbeeManager::createZigbeeNetwork(const QString &serialPort, const uint baudRate, const ZigbeeAdapter::ZigbeeBackendType backendType, const ZigbeeChannelMask channelMask) +QPair ZigbeeManager::createZigbeeNetwork(const QString &serialPort, uint baudRate, ZigbeeAdapter::ZigbeeBackendType backendType, ZigbeeChannelMask channelMask) { qCDebug(dcZigbee()) << "Start creating network for" << serialPort << baudRate << backendType << channelMask; @@ -287,12 +295,63 @@ void ZigbeeManager::loadZigbeeNetworks() return; } - // Start all loaded networks - foreach (ZigbeeNetwork *network, m_zigbeeNetworks.values()) { - network->startNetwork(); +} + +void ZigbeeManager::checkPlatformConfiguration() +{ + QFileInfo platformConfigurationFileInfo(NymeaSettings::settingsPath() + QDir::separator() + "zigbee-platform.conf"); + if (platformConfigurationFileInfo.exists()) { + qCDebug(dcZigbee()) << "Found zigbee platform configuration" << platformConfigurationFileInfo.absoluteFilePath(); + QSettings platformSettings(platformConfigurationFileInfo.absoluteFilePath(), QSettings::IniFormat); + QString serialPort = platformSettings.value("serialPort").toString(); + if (serialPort.isEmpty()) { + qCWarning(dcZigbee()) << "The serial port is not specified correctly in the platform configuration file" << platformConfigurationFileInfo.absoluteFilePath() << "The platform based network will not be created."; + return; + } + + if (!m_adapterMonitor->hasAdapter(serialPort)) { + qCWarning(dcZigbee()) << "Could not find platform specific serial port" << serialPort << "on this system. Please check the wiring or the port configuration. The platform based network will not be created."; + return; + } + + qint32 baudRate = platformSettings.value("baudRate").toUInt(); + QString backendString = platformSettings.value("backend").toString(); + Zigbee::ZigbeeBackendType backenType = Zigbee::ZigbeeBackendTypeNxp; + if (backendString.toLower().contains("deconz")) { + backenType = Zigbee::ZigbeeBackendTypeDeconz; + } + + bool alreadyCreated = false; + foreach (ZigbeeNetwork *network, m_zigbeeNetworks.values()) { + if (network->serialPortName() == serialPort && network->serialBaudrate() == baudRate && network->backendType() == backenType) { + qCDebug(dcZigbee()) << "Network based on platform configuration already created" << network; + alreadyCreated = true; + break; + } + } + + if (!alreadyCreated) { + qCDebug(dcZigbee()) << "Network based on platform configuration has not been created yet."; + ZigbeeNetwork *network = createPlatformNetwork(serialPort, baudRate, backenType); + addNetwork(network); + // Note: it will be saved once the network has started successfully + } + } else { + qCDebug(dcZigbee()) << "No platform configuration specified."; } } +ZigbeeNetwork *ZigbeeManager::createPlatformNetwork(const QString &serialPort, uint baudRate, Zigbee::ZigbeeBackendType backendType, ZigbeeChannelMask channelMask) +{ + qCDebug(dcZigbee()) << "Creating platform network on" << serialPort << baudRate << backendType << channelMask; + ZigbeeNetwork *network = ZigbeeNetworkManager::createZigbeeNetwork(QUuid::createUuid(), backendType); + network->setSettingsDirectory(QDir(NymeaSettings::settingsPath())); + network->setChannelMask(channelMask); + network->setSerialPortName(serialPort); + network->setSerialBaudrate(baudRate); + return network; +} + ZigbeeNetwork *ZigbeeManager::buildNetworkObject(const QUuid &networkId, ZigbeeAdapter::ZigbeeBackendType backendType) { ZigbeeNetwork *network = nullptr; diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index d235727d..c9b43a47 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -72,7 +72,7 @@ public: ZigbeeAdapters availableAdapters() const; QHash zigbeeNetworks() const; - QPair createZigbeeNetwork(const QString &serialPort, const uint baudRate, const ZigbeeAdapter::ZigbeeBackendType backendType, const ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); + QPair createZigbeeNetwork(const QString &serialPort, uint baudRate, ZigbeeAdapter::ZigbeeBackendType backendType, ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); ZigbeeError removeZigbeeNetwork(const QUuid &networkUuid); ZigbeeError setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, uint duration = 120); ZigbeeError factoryResetNetwork(const QUuid &networkUuid); @@ -87,6 +87,8 @@ private: void saveNetwork(ZigbeeNetwork *network); void loadZigbeeNetworks(); + void checkPlatformConfiguration(); + ZigbeeNetwork *createPlatformNetwork(const QString &serialPort, uint baudRate, Zigbee::ZigbeeBackendType backendType, ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); ZigbeeNetwork *buildNetworkObject(const QUuid &networkId, ZigbeeAdapter::ZigbeeBackendType backendType); void addNetwork(ZigbeeNetwork *network); From 2e6f68bc41a09b80d8d0b8ee8d3ba3b0de96204d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 18 Nov 2020 09:53:57 +0100 Subject: [PATCH 42/54] Fix typo in alert interface --- libnymea-core/libnymea-core.pro | 3 +-- libnymea/interfaces/alert.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 18b88770..4c9f5aff 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -1,4 +1,3 @@ - TEMPLATE = lib TARGET = nymea-core @@ -129,7 +128,7 @@ HEADERS += nymeacore.h \ tagging/tag.h \ cloud/cloudtransport.h \ debugreportgenerator.h \ - platform/platform.h \ \ + platform/platform.h \ zigbee/zigbeeadapter.h \ zigbee/zigbeeadapters.h \ zigbee/zigbeemanager.h \ diff --git a/libnymea/interfaces/alert.json b/libnymea/interfaces/alert.json index 65d01763..8e4bc8c9 100644 --- a/libnymea/interfaces/alert.json +++ b/libnymea/interfaces/alert.json @@ -1,5 +1,5 @@ { - "description": "Used for things that have some sort of alert. For instance, light bulbs may be able to blink on alert actions, or speaker might be able to play an alert sound. Zigbee devices for example oftion provide alert actions to identify themselves.", + "description": "Used for things that have some sort of alert. For instance, light bulbs may be able to blink on alert actions, or speaker might be able to play an alert sound. Zigbee devices for example often provide alert actions to identify themselves.", "actions": [ { "name": "alert" From e2cbffeebd8e3312aa5ee0ffd9f6d95475e47924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 18 Nov 2020 12:21:40 +0100 Subject: [PATCH 43/54] Make backend type dynamic and introduce GetAvailableBackends --- libnymea-core/jsonrpc/zigbeehandler.cpp | 86 +++++++++++++++---------- libnymea-core/jsonrpc/zigbeehandler.h | 1 + libnymea-core/zigbee/zigbeeadapter.cpp | 12 ++++ libnymea-core/zigbee/zigbeeadapter.h | 17 +++-- libnymea-core/zigbee/zigbeemanager.h | 3 +- 5 files changed, 76 insertions(+), 43 deletions(-) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index dc8f45ac..eb396a27 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -42,12 +42,8 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : m_zigbeeManager(zigbeeManager) { qRegisterMetaType(); - qRegisterMetaType(); - registerEnum(); - registerEnum(); registerEnum(); - registerObject(); // Network object describing a network instance @@ -64,54 +60,56 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : zigbeeNetworkDescription.insert("permitJoiningEnabled", enumValueName(Bool)); zigbeeNetworkDescription.insert("permitJoiningDuration", enumValueName(Uint)); zigbeeNetworkDescription.insert("permitJoiningRemaining", enumValueName(Uint)); - zigbeeNetworkDescription.insert("backendType", enumRef()); + zigbeeNetworkDescription.insert("backend", enumValueName(String)); zigbeeNetworkDescription.insert("networkState", enumRef()); registerObject("ZigbeeNetwork", zigbeeNetworkDescription); QVariantMap params, returns; QString description; + // GetAvailableBackends + params.clear(); returns.clear(); + description = "Get the list of available Zigbee backends."; + returns.insert("backends", QVariantList() << enumValueName(String)); + registerMethod("GetAvailableBackends", description, params, returns); + // GetAdapters params.clear(); returns.clear(); - description = "Get the list of available Zigbee adapter candidates in order to set up the zigbee network " - "on the desired serial interface. The serialPort property can be used as unique identifier. " - "If an adapter hardware has been recognized as a supported " - "hardware, the \'hardwareRecognized\' property will be true and the baud rate and backend " + description = "Get the list of available Zigbee adapters and serial ports in order to set up the Zigbee network " + "on the desired interface. The \'serialPort\' property can be used as unique identifier for an adapter. " + "If an adapter hardware has been recognized as a well known Zigbee adapter, " + "the \'hardwareRecognized\' property will be true and the \'baudRate\' and \'backend\' " "configurations can be used as they where given, otherwise the user might set the backend " - "type and baud rate manually."; + "and baud rate manually. The available backends can be fetched using the GetAvailableBackends method."; returns.insert("adapters", objectRef()); registerMethod("GetAdapters", description, params, returns); // AdapterAdded notification params.clear(); - description = "Emitted whenever a new Zigbee adapter candidate has been detected in the system."; + description = "Emitted whenever a new Zigbee adapter or serial port has been detected in the system."; params.insert("adapter", objectRef()); registerNotification("AdapterAdded", description, params); // AdapterRemoved notification params.clear(); - description = "Emitted whenever a Zigbee adapter has been removed from the system (i.e. unplugged)."; + description = "Emitted whenever a Zigbee adapter or serial port has been removed from the system (i.e. unplugged)."; params.insert("adapter", objectRef()); registerNotification("AdapterRemoved", description, params); // GetNetworks params.clear(); returns.clear(); - description = "Returns the list of zigbee networks configured in the system."; + description = "Returns the list of configured Zigbee networks in the system."; returns.insert("zigbeeNetworks", QVariantList() << objectRef("ZigbeeNetwork")); registerMethod("GetNetworks", description, params, returns); // AddNetwork params.clear(); returns.clear(); - description = "Create a new Zigbee network for the given serialPort, baud rate and backend type. " - "Get those information from the available Zigbee adapters." - "The channel mask is optional and defaults to all channels [11, 26]. " - "The quietest channel from the given channel mask will be picked during network creation. " - "The channel mask is a uint32 flag and the the bit number represents the channel which should " - "enabled for scanning. All channels would be the value 0x07fff800."; + description = "Create a new Zigbee network for the given \'serialPort\', \'baudRate\' and \'backend\'. " + "The serial ports can be fetched from the available adapters. See \'GetAdapters\' for more information. " + "The available backends can be fetched using the \'GetAvailableBackends\' method."; params.insert("serialPort", enumValueName(String)); params.insert("baudRate", enumValueName(Uint)); - params.insert("backendType", enumRef()); - params.insert("o:channelMask", enumValueName(Uint)); + params.insert("backend", enumValueName(String)); returns.insert("zigbeeError", enumRef()); returns.insert("o:networkUuid", enumValueName(Uuid)); registerMethod("AddNetwork", description, params, returns); @@ -143,22 +141,21 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // FactoryResetNetwork params.clear(); returns.clear(); - description = "Factory reset the network with the given networkUuid. The network does not have " - "to be Online for this procedure, and all associated nodes and things will be removed permanently. " - "Make sure the user realy wants to do this because this can not be undone."; + description = "Factory reset the network with the given \'networkUuid\'. The network does not have " + "to be online for this procedure, and all associated nodes and things will be removed permanently."; params.insert("networkUuid", enumValueName(Uuid)); returns.insert("zigbeeError", enumRef()); registerMethod("FactoryResetNetwork", description, params, returns); // SetPermitJoin params.clear(); returns.clear(); - description = "Allow or deny nodes to join the network with the given networkUuid for a specific duration in seconds. " - "The duration values has to be between 0 and 255 seconds. The permitJoinDuration indicates how long permit " - "has been enabled and the permitJoinDuration indicates the rest of the time. Those values can be used to " - "show a countdown or progressbar. This method can be recalled for resetting the timeout. " + description = "Allow or deny nodes to join the network with the given \'networkUuid\' for a specific \'duration\' in seconds. " + "The duration value has to be between 0 and 255 seconds. The \'permitJoinDuration\' property of Zigbee network " + "object indicates how long permit has been enabled and the \'permitJoiningRemaining\' indicates the rest of the time. " + "Those values can be used to show a countdown or progressbar. This method can be recalled for resetting the timeout. " "If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. " - "The shortAddress is optional and defaults to the broadcast address (0xfffc) for all routers in the network. " - "If the short address matches the address of a router node in the network, only that router will " + "The \'shortAddress\' is optional and defaults to the broadcast address 0xfffc for all routers in the network. " + "If the short address matches the address of a router node in the network, only that specific router will " "be able to allow new nodes to join the network. A new node will join to the router with the best link quality index (LQI)."; params.insert("networkUuid", enumValueName(Uuid)); params.insert("duration", enumValueName(Uint)); @@ -203,6 +200,19 @@ QString ZigbeeHandler::name() const return "Zigbee"; } +JsonReply *ZigbeeHandler::GetAvailableBackends(const QVariantMap ¶ms) +{ + Q_UNUSED(params) + + QVariantMap returnMap; + QVariantList backendsList; + foreach (const QString &backendName, ZigbeeAdapter::backendNames().values()) + backendsList << backendName; + + returnMap.insert("backends", backendsList); + return createReply(returnMap); +} + JsonReply *ZigbeeHandler::GetAdapters(const QVariantMap ¶ms) { Q_UNUSED(params) @@ -218,11 +228,17 @@ JsonReply *ZigbeeHandler::GetAdapters(const QVariantMap ¶ms) JsonReply *ZigbeeHandler::AddNetwork(const QVariantMap ¶ms) { + QVariantMap returnMap; + QString serialPort = params.value("serialPort").toString(); uint baudRate = params.value("baudRate").toUInt(); - ZigbeeAdapter::ZigbeeBackendType backendType = enumNameToValue(params.value("backendType").toString()); - QPair result = m_zigbeeManager->createZigbeeNetwork(serialPort, baudRate, backendType); - QVariantMap returnMap; + QString backendString = params.value("backend").toString(); + if (!ZigbeeAdapter::backendNames().values().contains(backendString)) { + returnMap.insert("zigbeeError", enumValueName(ZigbeeManager::ZigbeeErrorUnknownBackend)); + return createReply(returnMap); + } + + QPair result = m_zigbeeManager->createZigbeeNetwork(serialPort, baudRate, ZigbeeAdapter::backendNames().key(backendString)); if (result.first == ZigbeeManager::ZigbeeErrorNoError) { returnMap.insert("networkUuid", result.second); } @@ -293,10 +309,10 @@ QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network) switch (network->backendType()) { case Zigbee::ZigbeeBackendTypeDeconz: - networkMap.insert("backendType", enumValueName(ZigbeeAdapter::ZigbeeBackendTypeDeconz)); + networkMap.insert("backend", ZigbeeAdapter::backendNames().value(ZigbeeAdapter::ZigbeeBackendTypeDeconz)); break; case Zigbee::ZigbeeBackendTypeNxp: - networkMap.insert("backendType", enumValueName(ZigbeeAdapter::ZigbeeBackendTypeNxp)); + networkMap.insert("backend", ZigbeeAdapter::backendNames().value(ZigbeeAdapter::ZigbeeBackendTypeNxp)); break; } diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h index a5c6b614..0494c8af 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.h +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -49,6 +49,7 @@ public: QString name() const override; + Q_INVOKABLE JsonReply *GetAvailableBackends(const QVariantMap ¶ms); Q_INVOKABLE JsonReply *GetAdapters(const QVariantMap ¶ms); Q_INVOKABLE JsonReply *GetNetworks(const QVariantMap ¶ms); Q_INVOKABLE JsonReply *AddNetwork(const QVariantMap ¶ms); diff --git a/libnymea-core/zigbee/zigbeeadapter.cpp b/libnymea-core/zigbee/zigbeeadapter.cpp index 4b67b52b..43b411e6 100644 --- a/libnymea-core/zigbee/zigbeeadapter.cpp +++ b/libnymea-core/zigbee/zigbeeadapter.cpp @@ -97,6 +97,11 @@ void ZigbeeAdapter::setBackendType(ZigbeeAdapter::ZigbeeBackendType backendType) m_backendType = backendType; } +QString ZigbeeAdapter::backend() const +{ + return backendNames().value(m_backendType); +} + qint32 ZigbeeAdapter::baudRate() const { return m_baudRate; @@ -117,6 +122,13 @@ bool ZigbeeAdapter::operator==(const ZigbeeAdapter &other) const && m_baudRate == other.baudRate(); } +QHash ZigbeeAdapter::backendNames() +{ + QHash backendNameHash; + backendNameHash.insert(ZigbeeBackendTypeDeconz, "deCONZ"); + backendNameHash.insert(ZigbeeBackendTypeNxp, "NXP"); + return backendNameHash; +} QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter) { diff --git a/libnymea-core/zigbee/zigbeeadapter.h b/libnymea-core/zigbee/zigbeeadapter.h index 5712c728..a2419292 100644 --- a/libnymea-core/zigbee/zigbeeadapter.h +++ b/libnymea-core/zigbee/zigbeeadapter.h @@ -41,13 +41,13 @@ namespace nymeaserver { class ZigbeeAdapter { Q_GADGET - Q_PROPERTY(QString name READ name WRITE setName) - Q_PROPERTY(QString description READ description WRITE setDescription) - Q_PROPERTY(QString serialPort READ serialPort WRITE setSerialPort) - Q_PROPERTY(QString serialNumber READ serialNumber WRITE setSerialNumber) - Q_PROPERTY(bool hardwareRecognized READ hardwareRecognized WRITE setHardwareRecognized) - Q_PROPERTY(nymeaserver::ZigbeeAdapter::ZigbeeBackendType backendType READ backendType WRITE setBackendType) - Q_PROPERTY(qint32 baudRate READ baudRate WRITE setBaudRate) + Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString description READ description) + Q_PROPERTY(QString serialPort READ serialPort) + Q_PROPERTY(QString serialNumber READ serialNumber) + Q_PROPERTY(bool hardwareRecognized READ hardwareRecognized) + Q_PROPERTY(QString backend READ backend) + Q_PROPERTY(qint32 baudRate READ baudRate) public: enum ZigbeeBackendType { @@ -75,12 +75,15 @@ public: ZigbeeAdapter::ZigbeeBackendType backendType() const; void setBackendType(ZigbeeAdapter::ZigbeeBackendType backendType); + QString backend() const; qint32 baudRate() const; void setBaudRate(qint32 baudRate); bool operator==(const ZigbeeAdapter &other) const; + static QHash backendNames(); + private: QString m_name; QString m_description; diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index c9b43a47..0b4196ed 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -60,7 +60,8 @@ public: ZigbeeErrorAdapterAlreadyInUse, ZigbeeErrorNetworkUuidNotFound, ZigbeeErrorDurationOutOfRange, - ZigbeeErrorNetworkOffline + ZigbeeErrorNetworkOffline, + ZigbeeErrorUnknownBackend }; Q_ENUM(ZigbeeError) From 929ef2fb5ddd6e7e95da4c627dc1eb956f70939f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 18 Nov 2020 12:22:37 +0100 Subject: [PATCH 44/54] Update API json --- tests/auto/api.json | 50 +++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/tests/auto/api.json b/tests/auto/api.json index 8669fe75..97c762b6 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -365,17 +365,14 @@ "WirelessModeInfrastructure", "WirelessModeAccessPoint" ], - "ZigbeeBackendType": [ - "ZigbeeBackendTypeDeconz", - "ZigbeeBackendTypeNxp" - ], "ZigbeeError": [ "ZigbeeErrorNoError", "ZigbeeErrorAdapterNotAvailable", "ZigbeeErrorAdapterAlreadyInUse", "ZigbeeErrorNetworkUuidNotFound", "ZigbeeErrorDurationOutOfRange", - "ZigbeeErrorNetworkOffline" + "ZigbeeErrorNetworkOffline", + "ZigbeeErrorUnknownBackend" ], "ZigbeeNetworkState": [ "ZigbeeNetworkStateOffline", @@ -1953,11 +1950,10 @@ } }, "Zigbee.AddNetwork": { - "description": "Create a new Zigbee network for the given serialPort, baud rate and backend type. Get those information from the available Zigbee adapters.The channel mask is optional and defaults to all channels [11, 26]. The quietest channel from the given channel mask will be picked during network creation. The channel mask is a uint32 flag and the the bit number represents the channel which should enabled for scanning. All channels would be the value 0x07fff800.", + "description": "Create a new Zigbee network for the given 'serialPort', 'baudRate' and 'backend'. The serial ports can be fetched from the available adapters. See 'GetAdapters' for more information. The available backends can be fetched using the 'GetAvailableBackends' method.", "params": { - "backendType": "$ref:ZigbeeBackendType", + "backend": "String", "baudRate": "Uint", - "o:channelMask": "Uint", "serialPort": "String" }, "returns": { @@ -1966,7 +1962,7 @@ } }, "Zigbee.FactoryResetNetwork": { - "description": "Factory reset the network with the given networkUuid. The network does not have to be Online for this procedure, and all associated nodes and things will be removed permanently. Make sure the user realy wants to do this because this can not be undone.", + "description": "Factory reset the network with the given 'networkUuid'. The network does not have to be online for this procedure, and all associated nodes and things will be removed permanently.", "params": { "networkUuid": "Uuid" }, @@ -1975,15 +1971,25 @@ } }, "Zigbee.GetAdapters": { - "description": "Get the list of available Zigbee adapter candidates in order to set up the zigbee network on the desired serial interface. The serialPort property can be used as unique identifier. If an adapter hardware has been recognized as a supported hardware, the 'hardwareRecognized' property will be true and the baud rate and backend configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually.", + "description": "Get the list of available Zigbee adapters and serial ports in order to set up the Zigbee network on the desired interface. The 'serialPort' property can be used as unique identifier for an adapter. If an adapter hardware has been recognized as a well known Zigbee adapter, the 'hardwareRecognized' property will be true and the 'baudRate' and 'backend' configurations can be used as they where given, otherwise the user might set the backend and baud rate manually. The available backends can be fetched using the GetAvailableBackends method.", "params": { }, "returns": { "adapters": "$ref:ZigbeeAdapters" } }, + "Zigbee.GetAvailableBackends": { + "description": "Get the list of available Zigbee backends.", + "params": { + }, + "returns": { + "backends": [ + "String" + ] + } + }, "Zigbee.GetNetworks": { - "description": "Returns the list of zigbee networks configured in the system.", + "description": "Returns the list of configured Zigbee networks in the system.", "params": { }, "returns": { @@ -2002,7 +2008,7 @@ } }, "Zigbee.SetPermitJoin": { - "description": "Allow or deny nodes to join the network with the given networkUuid for a specific duration in seconds. The duration values has to be between 0 and 255 seconds. The permitJoinDuration indicates how long permit has been enabled and the permitJoinDuration indicates the rest of the time. Those values can be used to show a countdown or progressbar. This method can be recalled for resetting the timeout. If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. The shortAddress is optional and defaults to the broadcast address (0xfffc) for all routers in the network. If the short address matches the address of a router node in the network, only that router will be able to allow new nodes to join the network. A new node will join to the router with the best link quality index (LQI).", + "description": "Allow or deny nodes to join the network with the given 'networkUuid' for a specific 'duration' in seconds. The duration value has to be between 0 and 255 seconds. The 'permitJoinDuration' property of Zigbee network object indicates how long permit has been enabled and the 'permitJoiningRemaining' indicates the rest of the time. Those values can be used to show a countdown or progressbar. This method can be recalled for resetting the timeout. If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. The 'shortAddress' is optional and defaults to the broadcast address 0xfffc for all routers in the network. If the short address matches the address of a router node in the network, only that specific router will be able to allow new nodes to join the network. A new node will join to the router with the best link quality index (LQI).", "params": { "duration": "Uint", "networkUuid": "Uuid", @@ -2431,13 +2437,13 @@ } }, "Zigbee.AdapterAdded": { - "description": "Emitted whenever a new Zigbee adapter candidate has been detected in the system.", + "description": "Emitted whenever a new Zigbee adapter or serial port has been detected in the system.", "params": { "adapter": "$ref:ZigbeeAdapter" } }, "Zigbee.AdapterRemoved": { - "description": "Emitted whenever a Zigbee adapter has been removed from the system (i.e. unplugged).", + "description": "Emitted whenever a Zigbee adapter or serial port has been removed from the system (i.e. unplugged).", "params": { "adapter": "$ref:ZigbeeAdapter" } @@ -2930,19 +2936,19 @@ "r:state": "$ref:NetworkDeviceState" }, "ZigbeeAdapter": { - "backendType": "$ref:ZigbeeBackendType", - "baudRate": "Int", - "description": "String", - "hardwareRecognized": "Bool", - "name": "String", - "serialNumber": "String", - "serialPort": "String" + "r:backend": "String", + "r:baudRate": "Int", + "r:description": "String", + "r:hardwareRecognized": "Bool", + "r:name": "String", + "r:serialNumber": "String", + "r:serialPort": "String" }, "ZigbeeAdapters": [ "$ref:ZigbeeAdapter" ], "ZigbeeNetwork": { - "backendType": "$ref:ZigbeeBackendType", + "backend": "String", "baudRate": "Uint", "channel": "Uint", "channelMask": "Uint", From 527989fe7c30fd71f2154515748c324c0d700d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 19 Nov 2020 14:37:44 +0100 Subject: [PATCH 45/54] Ignore the coordinator node in the zigbee resource --- .../zigbee/zigbeehardwareresourceimplementation.cpp | 8 ++++++++ libnymea-core/zigbee/zigbeemanager.cpp | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index a7ef19a8..f7efd46b 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -169,6 +169,10 @@ void ZigbeeHardwareResourceImplementation::thingsLoaded() foreach (ZigbeeNetwork *network, m_zigbeeManager->zigbeeNetworks()) { if (network->state() == ZigbeeNetwork::StateRunning) { foreach (ZigbeeNode *node, network->nodes()) { + // Ignore the coordinator node + if (node->shortAddress() == 0x0000) + continue; + if (!m_nodeHandlers.contains(node)) { qCDebug(dcZigbeeResource()) << "Node" << node << "is not yet handled by any plugin. Trying to find a suitable plugin."; onZigbeeNodeAdded(network->networkUuid(), node); @@ -199,6 +203,10 @@ void ZigbeeHardwareResourceImplementation::onZigbeeNetworkChanged(ZigbeeNetwork // been installed now, such nodes might be handled by them now. if (network->state() == ZigbeeNetwork::StateRunning && m_thingsLoaded) { foreach (ZigbeeNode *node, network->nodes()) { + // Ignore the coordinator node + if (node->shortAddress() == 0x0000) + continue; + if (!m_nodeHandlers.contains(node)) { onZigbeeNodeAdded(network->networkUuid(), node); } diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 42c3ac43..374f7a35 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -299,6 +299,17 @@ void ZigbeeManager::loadZigbeeNetworks() void ZigbeeManager::checkPlatformConfiguration() { + /* Example platform configurations + * + * serialPort=/dev/ttymxc2 + * baudRate=115200 + * backend=nxp + * + * serialPort=/dev/ttyS0 + * baudRate=38400 + * backend=deconz + */ + QFileInfo platformConfigurationFileInfo(NymeaSettings::settingsPath() + QDir::separator() + "zigbee-platform.conf"); if (platformConfigurationFileInfo.exists()) { qCDebug(dcZigbee()) << "Found zigbee platform configuration" << platformConfigurationFileInfo.absoluteFilePath(); From 8749789322dec15abfc60a8b6521c3eb04cca6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 25 Nov 2020 13:05:27 +0100 Subject: [PATCH 46/54] Give plugins access to the coordinator IEEE address for unicast bindings --- .../zigbee/zigbeehardwareresourceimplementation.cpp | 10 ++++++++++ .../zigbee/zigbeehardwareresourceimplementation.h | 1 + libnymea-core/zigbee/zigbeemanager.cpp | 5 +++++ libnymea/hardware/zigbee/zigbeehardwareresource.h | 1 + 4 files changed, 17 insertions(+) diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp index f7efd46b..80a54cd5 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.cpp @@ -118,6 +118,16 @@ ZigbeeNetwork::State ZigbeeHardwareResourceImplementation::networkState(const QU return network->state(); } +ZigbeeAddress ZigbeeHardwareResourceImplementation::coordinatorAddress(const QUuid &networkUuid) +{ + ZigbeeNetwork *network = m_zigbeeManager->zigbeeNetworks().value(networkUuid); + if (!network) { + qCWarning(dcZigbeeResource()) << "Network" << networkUuid << "not found."; + return ZigbeeAddress(); + } + return network->coordinatorNode()->extendedAddress(); +} + void ZigbeeHardwareResourceImplementation::setEnabled(bool enabled) { qCDebug(dcZigbeeResource()) << "Set" << (enabled ? "enabled" : "disabled"); diff --git a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h index c01e2b8b..d14a093c 100644 --- a/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h +++ b/libnymea-core/hardware/zigbee/zigbeehardwareresourceimplementation.h @@ -54,6 +54,7 @@ public: void removeNodeFromNetwork(const QUuid &networkUuid, ZigbeeNode *node) override; ZigbeeNetwork::State networkState(const QUuid &networkUuid) override; + ZigbeeAddress coordinatorAddress(const QUuid &networkUuid) override; public slots: bool enable(); diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 374f7a35..be46a14d 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -132,6 +132,10 @@ QPair ZigbeeManager::createZigbeeNetwork(cons return QPair(ZigbeeManager::ZigbeeErrorAdapterNotAvailable, QUuid()); } +// ZigbeeChannelMask testChannelMask = ZigbeeChannelMask(0); +// testChannelMask.setChannel(Zigbee::ZigbeeChannel13); +// qCWarning(dcZigbee()) << "Using test channel mask" << testChannelMask; + ZigbeeNetwork *network = buildNetworkObject(QUuid::createUuid(), backendType); network->setChannelMask(channelMask); network->setSerialPortName(serialPort); @@ -452,6 +456,7 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) qCDebug(dcZigbee()) << " Model" << endpoint->modelIdentifier(); qCDebug(dcZigbee()) << " Version" << endpoint->softwareBuildId(); } + qCDebug(dcZigbee()) << " Input clusters (" << endpoint->inputClusters().count() << ")"; foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { qCDebug(dcZigbee()) << " -" << cluster; diff --git a/libnymea/hardware/zigbee/zigbeehardwareresource.h b/libnymea/hardware/zigbee/zigbeehardwareresource.h index 5f8a64a7..c4a7b860 100644 --- a/libnymea/hardware/zigbee/zigbeehardwareresource.h +++ b/libnymea/hardware/zigbee/zigbeehardwareresource.h @@ -59,6 +59,7 @@ public: virtual void removeNodeFromNetwork(const QUuid &networkUuid, ZigbeeNode *node) = 0; virtual ZigbeeNetwork::State networkState(const QUuid &networkUuid) = 0; + virtual ZigbeeAddress coordinatorAddress(const QUuid &networkUuid) = 0; signals: void networkStateChanged(const QUuid &networkUuid, ZigbeeNetwork::State state); From 66dbcc03af2bb75347606cfcc2add79a38a041b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sat, 28 Nov 2020 14:28:23 +0100 Subject: [PATCH 47/54] Remove node initializer since init process will be handled by the plugins --- libnymea-core/libnymea-core.pro | 6 +- libnymea-core/zigbee/zigbeemanager.cpp | 14 -- libnymea-core/zigbee/zigbeemanager.h | 2 - .../zigbee/zigbeenodeinitializer.cpp | 130 ------------------ libnymea-core/zigbee/zigbeenodeinitializer.h | 56 -------- 5 files changed, 2 insertions(+), 206 deletions(-) delete mode 100644 libnymea-core/zigbee/zigbeenodeinitializer.cpp delete mode 100644 libnymea-core/zigbee/zigbeenodeinitializer.h diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 4c9f5aff..ad87afc8 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -131,8 +131,7 @@ HEADERS += nymeacore.h \ platform/platform.h \ zigbee/zigbeeadapter.h \ zigbee/zigbeeadapters.h \ - zigbee/zigbeemanager.h \ - zigbee/zigbeenodeinitializer.h + zigbee/zigbeemanager.h SOURCES += nymeacore.cpp \ @@ -219,8 +218,7 @@ SOURCES += nymeacore.cpp \ platform/platform.cpp \ zigbee/zigbeeadapter.cpp \ zigbee/zigbeeadapters.cpp \ - zigbee/zigbeemanager.cpp \ - zigbee/zigbeenodeinitializer.cpp + zigbee/zigbeemanager.cpp versionAtLeast(QT_VERSION, 5.12.0) { diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index be46a14d..86ee191d 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -474,11 +474,6 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) } } - -// ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); -// nodeInitializer->initializeNode(node); - //TODO: emit node added once initialized so the plugins can use it - emit nodeAdded(network->networkUuid(), node); }); @@ -499,13 +494,6 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) m_zigbeeNetworks.insert(network->networkUuid(), network); emit zigbeeNetworkAdded(network); - // Create node initializer when a new node joins the network - ZigbeeNodeInitializer *nodeInitializer = new ZigbeeNodeInitializer(network, this); - connect(nodeInitializer, &ZigbeeNodeInitializer::nodeInitialized, this, [this, network](ZigbeeNode *node){ - qCDebug(dcZigbee()) << "Node initialied from nymea" << node; - emit nodeAdded(network->networkUuid(), node); - }); - qCDebug(dcZigbee()) << "Network added" << network; foreach (ZigbeeNode *node, network->nodes()) { qCDebug(dcZigbee()) << "-->" << node; @@ -533,8 +521,6 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) } } } - - m_zigbeeNodeInitializers.insert(network->networkUuid(), nodeInitializer); } ZigbeeAdapter ZigbeeManager::convertUartAdapterToAdapter(const ZigbeeUartAdapter &uartAdapter) diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index 0b4196ed..84a39211 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -37,7 +37,6 @@ #include #include "zigbeeadapters.h" -#include "zigbeenodeinitializer.h" namespace nymeaserver { @@ -82,7 +81,6 @@ private: ZigbeeAdapters m_adapters; ZigbeeUartAdapterMonitor *m_adapterMonitor = nullptr; QHash m_zigbeeNetworks; - QHash m_zigbeeNodeInitializers; bool m_available = false; diff --git a/libnymea-core/zigbee/zigbeenodeinitializer.cpp b/libnymea-core/zigbee/zigbeenodeinitializer.cpp deleted file mode 100644 index b7a5c6de..00000000 --- a/libnymea-core/zigbee/zigbeenodeinitializer.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* 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 . -* -* 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 "zigbeenodeinitializer.h" -#include "loggingcategories.h" - -#include - -Q_DECLARE_LOGGING_CATEGORY(dcZigbee) - -ZigbeeNodeInitializer::ZigbeeNodeInitializer(ZigbeeNetwork *network, QObject *parent) : - QObject(parent), - m_network(network) -{ - -} - -void ZigbeeNodeInitializer::initializeNode(ZigbeeNode *node) -{ - qCDebug(dcZigbee()) << "Start initializing node internally" << node; - - // Bind the coordinator to group 0x0000 - //m_network->coordinatorNode()->deviceObject()->requestBindShortAddress(0x01, ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000); - - // Initialize and configure server clusters - foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { - // Configure attribute reporting - if (endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { - - // Read current battery remaining - qCDebug(dcZigbee()) << "Read power configuration cluster attributes" << node; - ZigbeeClusterReply *readAttributeReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining}); - connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){ - if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) { - qCWarning(dcZigbee()) << "Failed to read power cluster attributes" << readAttributeReply->error(); - //emit nodeInitialized(node); - return; - } - qCDebug(dcZigbee()) << "Read power configuration cluster attributes finished successfully"; - - // Bind the cluster to the coordinator - qCDebug(dcZigbee()) << "Bind power configuration cluster to coordinaotr"; - ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, m_network->coordinatorNode()->extendedAddress(), 0x01); - connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ - if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { - qCWarning(dcZigbee()) << "Failed to bind power cluster to coordinator" << readAttributeReply->error(); - return; - } - qCDebug(dcZigbee()) << "Bind power configuration cluster to coordinaotr finished successfully"; - - // Configure attribute rporting for battery remaining - ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; - reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; - reportingConfig.dataType = Zigbee::Uint8; - reportingConfig.minReportingInterval = 300; - reportingConfig.maxReportingInterval = 2700; - reportingConfig.reportableChange = ZigbeeDataType(static_cast(14)).data(); - - qCDebug(dcZigbee()) << "Configure attribute reporting for power configuration cluster to coordinator"; - ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); - connect(reportingReply, &ZigbeeClusterReply::finished, this, [reportingReply](){ - if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { - qCWarning(dcZigbee()) << "Failed to read power cluster attributes" << reportingReply->error(); - return; - } - - qCDebug(dcZigbee()) << "Reporting config finished" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); - }); - }); - }); - } - } - - - // Initialize and configure client clusters - foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { - - if (endpoint->hasOutputCluster(ZigbeeClusterLibrary::ClusterIdOnOff)) { - // Bind command - ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, m_network->coordinatorNode()->shortAddress()); - connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [zdoReply](){ - if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { - qCWarning(dcZigbee()) << "Failed to bind OnOff cluster attributes" << zdoReply->error(); - return; - } - }); - } - - if (endpoint->hasOutputCluster(ZigbeeClusterLibrary::ClusterIdLevelControl)) { - // Bind command - ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, m_network->coordinatorNode()->shortAddress()); - connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [this, node, zdoReply](){ - if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { - qCWarning(dcZigbee()) << "Failed to bind Level cluster attributes" << zdoReply->error(); - //emit nodeInitialized(node); - return; - } - }); - } - } - - //emit nodeInitialized(node); -} diff --git a/libnymea-core/zigbee/zigbeenodeinitializer.h b/libnymea-core/zigbee/zigbeenodeinitializer.h deleted file mode 100644 index 7bfe5304..00000000 --- a/libnymea-core/zigbee/zigbeenodeinitializer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* 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 . -* -* 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 ZIGBEENODEINITIALIZER_H -#define ZIGBEENODEINITIALIZER_H - -#include - -class ZigbeeNode; -class ZigbeeNetwork; - -class ZigbeeNodeInitializer : public QObject -{ - Q_OBJECT -public: - explicit ZigbeeNodeInitializer(ZigbeeNetwork *network, QObject *parent = nullptr); - - void initializeNode(ZigbeeNode *node); - -private: - ZigbeeNetwork *m_network = nullptr; - - - -signals: - void nodeInitialized(ZigbeeNode *node); -}; - -#endif // ZIGBEENODEINITIALIZER_H From bbc03066b4a0cbb3f39cb169c939d1ec0ffe91f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 30 Nov 2020 17:43:29 +0100 Subject: [PATCH 48/54] Remove node reachable evaluation and move it to the network itself --- libnymea-core/zigbee/zigbeemanager.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 86ee191d..493214d6 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -387,16 +387,6 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) connect(network, &ZigbeeNetwork::stateChanged, this, [this, network](ZigbeeNetwork::State state){ Q_UNUSED(state) qCDebug(dcZigbee()) << "Network state changed" << network; - if (state == ZigbeeNetwork::StateRunning) { - - // Send a broadcast request to all powered nodes - foreach (ZigbeeNode *node, network->nodes()) { - if (node->macCapabilities().receiverOnWhenIdle && node->shortAddress() != 0x0000) { - node->deviceObject()->requestMgmtLqi(); - } - } - } - evaluateZigbeeAvailable(); emit zigbeeNetworkChanged(network); }); @@ -566,4 +556,5 @@ void ZigbeeManager::evaluateZigbeeAvailable() emit availableChanged(m_available); } + } From 402ba069a1a85aac062d0a30379fb46a4a868acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 9 Dec 2020 17:20:04 +0100 Subject: [PATCH 49/54] Improve debug prints for better reading of joining nodes --- libnymea-core/zigbee/zigbeemanager.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 493214d6..2f507917 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -441,11 +441,14 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) qCDebug(dcZigbee()) << "-->" << node; foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { qCDebug(dcZigbee()) << " " << endpoint; - if (!endpoint->manufacturerName().isEmpty()) { - qCDebug(dcZigbee()) << " Manufacturer" << endpoint->manufacturerName(); + if (!endpoint->manufacturerName().isEmpty()) + qCDebug(dcZigbee()) << " Manufacturer:" << endpoint->manufacturerName(); + + if (!endpoint->modelIdentifier().isEmpty()) qCDebug(dcZigbee()) << " Model" << endpoint->modelIdentifier(); + + if (!endpoint->softwareBuildId().isEmpty()) qCDebug(dcZigbee()) << " Version" << endpoint->softwareBuildId(); - } qCDebug(dcZigbee()) << " Input clusters (" << endpoint->inputClusters().count() << ")"; foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { @@ -489,11 +492,15 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) qCDebug(dcZigbee()) << "-->" << node; foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { qCDebug(dcZigbee()) << " " << endpoint; - if (!endpoint->manufacturerName().isEmpty()) { - qCDebug(dcZigbee()) << " Manufacturer" << endpoint->manufacturerName(); + if (!endpoint->manufacturerName().isEmpty()) + qCDebug(dcZigbee()) << " Manufacturer:" << endpoint->manufacturerName(); + + if (!endpoint->modelIdentifier().isEmpty()) qCDebug(dcZigbee()) << " Model" << endpoint->modelIdentifier(); + + if (!endpoint->softwareBuildId().isEmpty()) qCDebug(dcZigbee()) << " Version" << endpoint->softwareBuildId(); - } + qCDebug(dcZigbee()) << " Input clusters (" << endpoint->inputClusters().count() << ")"; foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { qCDebug(dcZigbee()) << " -" << cluster; From 0cf7679341a8a5ff69fcccb942f561c7bd98ef1c Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 14 Dec 2020 23:32:11 +0100 Subject: [PATCH 50/54] revert newline change to avoid conflicts --- libnymea/loggingcategories.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp index 987b00e2..45906af3 100644 --- a/libnymea/loggingcategories.cpp +++ b/libnymea/loggingcategories.cpp @@ -77,6 +77,7 @@ NYMEA_LOGGING_CATEGORY(dcMqtt, "Mqtt") NYMEA_LOGGING_CATEGORY(dcTranslations, "Translations") NYMEA_LOGGING_CATEGORY(dcI2C, "I2C") + static QFile s_logFile; static bool s_useColors; static QList s_handlers; From d51327b97ae1556a4d5f523cfc12be351e149d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 16 Dec 2020 12:59:00 +0100 Subject: [PATCH 51/54] Update JSON RPC descriptions and rename Zigbee to ZigBee --- libnymea-core/jsonrpc/zigbeehandler.cpp | 24 ++++++++++++------------ tests/auto/api.json | 22 +++++++++++----------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index eb396a27..66774f7e 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -69,15 +69,15 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // GetAvailableBackends params.clear(); returns.clear(); - description = "Get the list of available Zigbee backends."; + description = "Get the list of available ZigBee backends."; returns.insert("backends", QVariantList() << enumValueName(String)); registerMethod("GetAvailableBackends", description, params, returns); // GetAdapters params.clear(); returns.clear(); - description = "Get the list of available Zigbee adapters and serial ports in order to set up the Zigbee network " + description = "Get the list of available ZigBee adapters and serial ports in order to set up the ZigBee network " "on the desired interface. The \'serialPort\' property can be used as unique identifier for an adapter. " - "If an adapter hardware has been recognized as a well known Zigbee adapter, " + "If an adapter hardware has been recognized as a well known ZigBee adapter, " "the \'hardwareRecognized\' property will be true and the \'baudRate\' and \'backend\' " "configurations can be used as they where given, otherwise the user might set the backend " "and baud rate manually. The available backends can be fetched using the GetAvailableBackends method."; @@ -86,25 +86,25 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // AdapterAdded notification params.clear(); - description = "Emitted whenever a new Zigbee adapter or serial port has been detected in the system."; + description = "Emitted whenever a new ZigBee adapter or serial port has been detected in the system."; params.insert("adapter", objectRef()); registerNotification("AdapterAdded", description, params); // AdapterRemoved notification params.clear(); - description = "Emitted whenever a Zigbee adapter or serial port has been removed from the system (i.e. unplugged)."; + description = "Emitted whenever a ZigBee adapter or serial port has been removed from the system (i.e. unplugged)."; params.insert("adapter", objectRef()); registerNotification("AdapterRemoved", description, params); // GetNetworks params.clear(); returns.clear(); - description = "Returns the list of configured Zigbee networks in the system."; + description = "Returns the list of configured ZigBee networks in the system."; returns.insert("zigbeeNetworks", QVariantList() << objectRef("ZigbeeNetwork")); registerMethod("GetNetworks", description, params, returns); // AddNetwork params.clear(); returns.clear(); - description = "Create a new Zigbee network for the given \'serialPort\', \'baudRate\' and \'backend\'. " + description = "Create a new ZigBee network for the given \'serialPort\', \'baudRate\' and \'backend\'. " "The serial ports can be fetched from the available adapters. See \'GetAdapters\' for more information. " "The available backends can be fetched using the \'GetAvailableBackends\' method."; params.insert("serialPort", enumValueName(String)); @@ -116,26 +116,26 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // RemoveNetwork params.clear(); returns.clear(); - description = "Remove the zigbee network with the given network uuid."; + description = "Remove the ZigBee network with the given network uuid."; params.insert("networkUuid", enumValueName(Uuid)); returns.insert("zigbeeError", enumRef()); registerMethod("RemoveNetwork", description, params, returns); // NetworkAdded notification params.clear(); - description = "Emitted whenever a new Zigbee network has been added."; + description = "Emitted whenever a new ZigBee network has been added."; params.insert("zigbeeNetwork", objectRef("ZigbeeNetwork")); registerNotification("NetworkAdded", description, params); // NetworkRemoved notification params.clear(); - description = "Emitted whenever a new Zigbee network has been removed."; + description = "Emitted whenever a new ZigBee network has been removed."; params.insert("networkUuid", enumValueName(Uuid)); registerNotification("NetworkRemoved", description, params); // NetworkChanged notification params.clear(); - description = "Emitted whenever a new Zigbee network has changed."; + description = "Emitted whenever a new ZigBee network has changed."; params.insert("zigbeeNetwork", objectRef("ZigbeeNetwork")); registerNotification("NetworkChanged", description, params); @@ -150,7 +150,7 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // SetPermitJoin params.clear(); returns.clear(); description = "Allow or deny nodes to join the network with the given \'networkUuid\' for a specific \'duration\' in seconds. " - "The duration value has to be between 0 and 255 seconds. The \'permitJoinDuration\' property of Zigbee network " + "The duration value has to be between 0 and 255 seconds. The \'permitJoinDuration\' property of ZigBee network " "object indicates how long permit has been enabled and the \'permitJoiningRemaining\' indicates the rest of the time. " "Those values can be used to show a countdown or progressbar. This method can be recalled for resetting the timeout. " "If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. " diff --git a/tests/auto/api.json b/tests/auto/api.json index 97c762b6..41551894 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1950,7 +1950,7 @@ } }, "Zigbee.AddNetwork": { - "description": "Create a new Zigbee network for the given 'serialPort', 'baudRate' and 'backend'. The serial ports can be fetched from the available adapters. See 'GetAdapters' for more information. The available backends can be fetched using the 'GetAvailableBackends' method.", + "description": "Create a new ZigBee network for the given 'serialPort', 'baudRate' and 'backend'. The serial ports can be fetched from the available adapters. See 'GetAdapters' for more information. The available backends can be fetched using the 'GetAvailableBackends' method.", "params": { "backend": "String", "baudRate": "Uint", @@ -1971,7 +1971,7 @@ } }, "Zigbee.GetAdapters": { - "description": "Get the list of available Zigbee adapters and serial ports in order to set up the Zigbee network on the desired interface. The 'serialPort' property can be used as unique identifier for an adapter. If an adapter hardware has been recognized as a well known Zigbee adapter, the 'hardwareRecognized' property will be true and the 'baudRate' and 'backend' configurations can be used as they where given, otherwise the user might set the backend and baud rate manually. The available backends can be fetched using the GetAvailableBackends method.", + "description": "Get the list of available ZigBee adapters and serial ports in order to set up the ZigBee network on the desired interface. The 'serialPort' property can be used as unique identifier for an adapter. If an adapter hardware has been recognized as a well known ZigBee adapter, the 'hardwareRecognized' property will be true and the 'baudRate' and 'backend' configurations can be used as they where given, otherwise the user might set the backend and baud rate manually. The available backends can be fetched using the GetAvailableBackends method.", "params": { }, "returns": { @@ -1979,7 +1979,7 @@ } }, "Zigbee.GetAvailableBackends": { - "description": "Get the list of available Zigbee backends.", + "description": "Get the list of available ZigBee backends.", "params": { }, "returns": { @@ -1989,7 +1989,7 @@ } }, "Zigbee.GetNetworks": { - "description": "Returns the list of configured Zigbee networks in the system.", + "description": "Returns the list of configured ZigBee networks in the system.", "params": { }, "returns": { @@ -1999,7 +1999,7 @@ } }, "Zigbee.RemoveNetwork": { - "description": "Remove the zigbee network with the given network uuid.", + "description": "Remove the ZigBee network with the given network uuid.", "params": { "networkUuid": "Uuid" }, @@ -2008,7 +2008,7 @@ } }, "Zigbee.SetPermitJoin": { - "description": "Allow or deny nodes to join the network with the given 'networkUuid' for a specific 'duration' in seconds. The duration value has to be between 0 and 255 seconds. The 'permitJoinDuration' property of Zigbee network object indicates how long permit has been enabled and the 'permitJoiningRemaining' indicates the rest of the time. Those values can be used to show a countdown or progressbar. This method can be recalled for resetting the timeout. If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. The 'shortAddress' is optional and defaults to the broadcast address 0xfffc for all routers in the network. If the short address matches the address of a router node in the network, only that specific router will be able to allow new nodes to join the network. A new node will join to the router with the best link quality index (LQI).", + "description": "Allow or deny nodes to join the network with the given 'networkUuid' for a specific 'duration' in seconds. The duration value has to be between 0 and 255 seconds. The 'permitJoinDuration' property of ZigBee network object indicates how long permit has been enabled and the 'permitJoiningRemaining' indicates the rest of the time. Those values can be used to show a countdown or progressbar. This method can be recalled for resetting the timeout. If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. The 'shortAddress' is optional and defaults to the broadcast address 0xfffc for all routers in the network. If the short address matches the address of a router node in the network, only that specific router will be able to allow new nodes to join the network. A new node will join to the router with the best link quality index (LQI).", "params": { "duration": "Uint", "networkUuid": "Uuid", @@ -2437,31 +2437,31 @@ } }, "Zigbee.AdapterAdded": { - "description": "Emitted whenever a new Zigbee adapter or serial port has been detected in the system.", + "description": "Emitted whenever a new ZigBee adapter or serial port has been detected in the system.", "params": { "adapter": "$ref:ZigbeeAdapter" } }, "Zigbee.AdapterRemoved": { - "description": "Emitted whenever a Zigbee adapter or serial port has been removed from the system (i.e. unplugged).", + "description": "Emitted whenever a ZigBee adapter or serial port has been removed from the system (i.e. unplugged).", "params": { "adapter": "$ref:ZigbeeAdapter" } }, "Zigbee.NetworkAdded": { - "description": "Emitted whenever a new Zigbee network has been added.", + "description": "Emitted whenever a new ZigBee network has been added.", "params": { "zigbeeNetwork": "$ref:ZigbeeNetwork" } }, "Zigbee.NetworkChanged": { - "description": "Emitted whenever a new Zigbee network has changed.", + "description": "Emitted whenever a new ZigBee network has changed.", "params": { "zigbeeNetwork": "$ref:ZigbeeNetwork" } }, "Zigbee.NetworkRemoved": { - "description": "Emitted whenever a new Zigbee network has been removed.", + "description": "Emitted whenever a new ZigBee network has been removed.", "params": { "networkUuid": "Uuid" } From 72a68df345cf4699f36a5d0ba46cdf2f4105baed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 16 Dec 2020 13:06:50 +0100 Subject: [PATCH 52/54] Add docs and missing license header --- libnymea/hardware/zigbee/zigbeehandler.cpp | 30 ++++++++++++++++++++++ libnymea/hardware/zigbee/zigbeehandler.h | 30 ++++++++++++++++++++++ libnymea/hardwaremanager.cpp | 4 +++ 3 files changed, 64 insertions(+) diff --git a/libnymea/hardware/zigbee/zigbeehandler.cpp b/libnymea/hardware/zigbee/zigbeehandler.cpp index a11a697d..9d5a209a 100644 --- a/libnymea/hardware/zigbee/zigbeehandler.cpp +++ b/libnymea/hardware/zigbee/zigbeehandler.cpp @@ -1,3 +1,33 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "zigbeehandler.h" ZigbeeHandler::ZigbeeHandler() diff --git a/libnymea/hardware/zigbee/zigbeehandler.h b/libnymea/hardware/zigbee/zigbeehandler.h index dba0d794..52f7b10f 100644 --- a/libnymea/hardware/zigbee/zigbeehandler.h +++ b/libnymea/hardware/zigbee/zigbeehandler.h @@ -1,3 +1,33 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 ZIGBEEHANDLER_H #define ZIGBEEHANDLER_H diff --git a/libnymea/hardwaremanager.cpp b/libnymea/hardwaremanager.cpp index 12aa022b..5141e605 100644 --- a/libnymea/hardwaremanager.cpp +++ b/libnymea/hardwaremanager.cpp @@ -69,6 +69,10 @@ Returns the MqttProvider \l{HardwareResource}. */ +/*! \fn ZigbeeHardwareResource *HardwareManager::zigbeeResource(); + Returns the Zigbee \l{HardwareResource}. +*/ + #include "hardwaremanager.h" #include "hardwareresource.h" From e32622dd2fa48abc83f8e87e450bdf4733c7f936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 16 Dec 2020 13:18:03 +0100 Subject: [PATCH 53/54] Set minimum required libnymea-zigbee-dev version for building --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index d1df3fd3..815fb606 100644 --- a/debian/control +++ b/debian/control @@ -12,7 +12,7 @@ Build-Depends: debhelper (>= 9.0.0), libnymea-mqtt-dev (>= 0.1.2), libnymea-networkmanager-dev (>= 0.4.0), libnymea-remoteproxyclient-dev, - libnymea-zigbee-dev, + libnymea-zigbee-dev (>= 0.1.0), libpython3-dev, libqt5websockets5-dev, libqt5bluetooth5, From 5ab371afdc99da3eed0f2207cbeeb2a2d5f3697e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 18 Dec 2020 15:35:57 +0100 Subject: [PATCH 54/54] Implement auto setup platform mechanism and add uart serialnumber verification --- libnymea-core/zigbee/zigbeemanager.cpp | 109 ++++++++++++++++++++----- libnymea-core/zigbee/zigbeemanager.h | 2 + 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 2f507917..eead3535 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -67,6 +67,22 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : qCDebug(dcZigbee()) << "Adapter added" << adapter; m_adapters.append(adapter); + + + if (m_autoSetupAdapters) { + if (networkExistsForAdapter(uartAdapter)) { + qCDebug(dcZigbee()) << "Auto setup enabled. There is already a network configured for" << uartAdapter; + } else { + qCDebug(dcZigbee()) << "Auto setup enabled. No network for" << uartAdapter << "created yet. Creating network..."; + ZigbeeNetwork *network = createPlatformNetwork(uartAdapter.serialPort(), uartAdapter.baudRate(), uartAdapter.zigbeeBackend()); + if (!uartAdapter.serialNumber().isEmpty()) + network->setSerialNumber(uartAdapter.serialNumber()); + + addNetwork(network); + network->startNetwork(); + } + } + // FIXME: check if serial number available and gets used by a network (adjust serial port if changed) emit availableAdapterAdded(adapter); @@ -88,6 +104,23 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : // Check if we have a zigbee platform configuration and if we have to create the platform network automatically checkPlatformConfiguration(); + // Check if auto setup recognized adapters is enabled + if (m_autoSetupAdapters) { + qCDebug(dcZigbee()) << "Auto setup enabled. Verify existing networks and adapters..."; + foreach(const ZigbeeUartAdapter &uartAdapter, m_adapterMonitor->availableAdapters()) { + if (networkExistsForAdapter(uartAdapter)) { + qCDebug(dcZigbee()) << "Network for adapter" << uartAdapter << "already created."; + } else { + qCDebug(dcZigbee()) << "Auto setup enabled and there is no network for" << uartAdapter << "created yet. Creating network..."; + ZigbeeNetwork *network = createPlatformNetwork(uartAdapter.serialPort(), uartAdapter.baudRate(), uartAdapter.zigbeeBackend()); + if (!uartAdapter.serialNumber().isEmpty()) + network->setSerialNumber(uartAdapter.serialNumber()); + + addNetwork(network); + } + } + } + // Start all loaded networks foreach (ZigbeeNetwork *network, m_zigbeeNetworks.values()) { network->startNetwork(); @@ -126,20 +159,23 @@ QPair ZigbeeManager::createZigbeeNetwork(cons } } - if (!m_adapters.hasSerialPort(serialPort)) { qCWarning(dcZigbee()) << "Failed to create a network for" << serialPort << "because the adapter is not available any more"; return QPair(ZigbeeManager::ZigbeeErrorAdapterNotAvailable, QUuid()); } -// ZigbeeChannelMask testChannelMask = ZigbeeChannelMask(0); -// testChannelMask.setChannel(Zigbee::ZigbeeChannel13); -// qCWarning(dcZigbee()) << "Using test channel mask" << testChannelMask; + QString serialNumber; + foreach (const ZigbeeAdapter &adapter, m_adapters) { + if (adapter.serialPort() == serialPort && !adapter.serialNumber().isEmpty()) { + serialNumber = adapter.serialNumber(); + } + } ZigbeeNetwork *network = buildNetworkObject(QUuid::createUuid(), backendType); network->setChannelMask(channelMask); network->setSerialPortName(serialPort); network->setSerialBaudrate(baudRate); + network->setSerialNumber(serialNumber); addNetwork(network); qCDebug(dcZigbee()) << "Starting" << network; @@ -240,8 +276,9 @@ void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) settings.setValue("channelMask", network->channelMask().toUInt32()); settings.setValue("networkKey", network->securityConfiguration().networkKey().toString()); settings.setValue("trustCenterLinkKey", network->securityConfiguration().globalTrustCenterLinkKey().toString()); - - // FIXME: save also the serial number of the port if available. + if (!network->serialNumber().isEmpty()) { + settings.setValue("serialNumber", network->serialNumber()); + } settings.endGroup(); // networkUuid settings.endGroup(); // ZigbeeNetworks @@ -259,6 +296,7 @@ void ZigbeeManager::loadZigbeeNetworks() QUuid networkUuid = QUuid(networkUuidGroupString); QString serialPortName = settings.value("serialPort").toString(); + QString serialNumber = settings.value("serialNumber").toString(); qint32 serialBaudRate = settings.value("baudRate").toInt(); ZigbeeAdapter::ZigbeeBackendType backendType = static_cast(settings.value("backendType").toInt()); quint16 panId = static_cast(settings.value("panId", 0).toUInt()); @@ -279,6 +317,7 @@ void ZigbeeManager::loadZigbeeNetworks() ZigbeeNetwork *network = buildNetworkObject(networkUuid, backendType); network->setSerialPortName(serialPortName); network->setSerialBaudrate(serialBaudRate); + network->setSerialNumber(serialNumber); network->setMacAddress(macAddress); network->setPanId(panId); network->setChannel(channel); @@ -304,21 +343,33 @@ void ZigbeeManager::loadZigbeeNetworks() void ZigbeeManager::checkPlatformConfiguration() { /* Example platform configurations - * - * serialPort=/dev/ttymxc2 - * baudRate=115200 - * backend=nxp - * - * serialPort=/dev/ttyS0 - * baudRate=38400 - * backend=deconz - */ + * + * serialPort=/dev/ttymxc2 + * baudRate=115200 + * backend=nxp + * autoSetup=false + * + * serialPort=/dev/ttyS0 + * baudRate=38400 + * backend=deconz + * autoSetup=false + * + * autoSetup=true + */ QFileInfo platformConfigurationFileInfo(NymeaSettings::settingsPath() + QDir::separator() + "zigbee-platform.conf"); if (platformConfigurationFileInfo.exists()) { qCDebug(dcZigbee()) << "Found zigbee platform configuration" << platformConfigurationFileInfo.absoluteFilePath(); QSettings platformSettings(platformConfigurationFileInfo.absoluteFilePath(), QSettings::IniFormat); QString serialPort = platformSettings.value("serialPort").toString(); + qint32 baudRate = platformSettings.value("baudRate").toUInt(); + QString backendString = platformSettings.value("backend").toString(); + m_autoSetupAdapters = platformSettings.value("autoSetup").toBool(); + Zigbee::ZigbeeBackendType backenType = Zigbee::ZigbeeBackendTypeNxp; + if (backendString.toLower().contains("deconz")) { + backenType = Zigbee::ZigbeeBackendTypeDeconz; + } + if (serialPort.isEmpty()) { qCWarning(dcZigbee()) << "The serial port is not specified correctly in the platform configuration file" << platformConfigurationFileInfo.absoluteFilePath() << "The platform based network will not be created."; return; @@ -329,13 +380,6 @@ void ZigbeeManager::checkPlatformConfiguration() return; } - qint32 baudRate = platformSettings.value("baudRate").toUInt(); - QString backendString = platformSettings.value("backend").toString(); - Zigbee::ZigbeeBackendType backenType = Zigbee::ZigbeeBackendTypeNxp; - if (backendString.toLower().contains("deconz")) { - backenType = Zigbee::ZigbeeBackendTypeDeconz; - } - bool alreadyCreated = false; foreach (ZigbeeNetwork *network, m_zigbeeNetworks.values()) { if (network->serialPortName() == serialPort && network->serialBaudrate() == baudRate && network->backendType() == backenType) { @@ -356,6 +400,27 @@ void ZigbeeManager::checkPlatformConfiguration() } } +bool ZigbeeManager::networkExistsForAdapter(const ZigbeeUartAdapter &uartAdapter) +{ + bool networkCreated = false; + foreach (ZigbeeNetwork *network, m_zigbeeNetworks) { + // Use the serial number if possible as refference + if (!uartAdapter.serialNumber().isEmpty()) { + if (network->serialNumber() == uartAdapter.serialNumber()) { + networkCreated = true; + break; + } + } + + // Otherwise check the serial port + if (network->serialPortName() == uartAdapter.serialPort()) { + networkCreated = true; + break; + } + } + return networkCreated; +} + ZigbeeNetwork *ZigbeeManager::createPlatformNetwork(const QString &serialPort, uint baudRate, Zigbee::ZigbeeBackendType backendType, ZigbeeChannelMask channelMask) { qCDebug(dcZigbee()) << "Creating platform network on" << serialPort << baudRate << backendType << channelMask; diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index 84a39211..3e829043 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -83,10 +83,12 @@ private: QHash m_zigbeeNetworks; bool m_available = false; + bool m_autoSetupAdapters = false; void saveNetwork(ZigbeeNetwork *network); void loadZigbeeNetworks(); void checkPlatformConfiguration(); + bool networkExistsForAdapter(const ZigbeeUartAdapter &uartAdapter); ZigbeeNetwork *createPlatformNetwork(const QString &serialPort, uint baudRate, Zigbee::ZigbeeBackendType backendType, ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); ZigbeeNetwork *buildNetworkObject(const QUuid &networkId, ZigbeeAdapter::ZigbeeBackendType backendType);