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] 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);