diff --git a/libnymea-app/engine.cpp b/libnymea-app/engine.cpp index fbfa0a11..b26215cc 100644 --- a/libnymea-app/engine.cpp +++ b/libnymea-app/engine.cpp @@ -154,6 +154,7 @@ void Engine::onDeviceManagerFetchingChanged() m_scriptManager->init(); m_nymeaConfiguration->init(); m_systemController->init(); + if (m_jsonRpcClient->ensureServerVersion("1.7")) { m_tagsManager->init(); } diff --git a/libnymea-app/libnymea-app-core.h b/libnymea-app/libnymea-app-core.h index f97b7719..c5e72b51 100644 --- a/libnymea-app/libnymea-app-core.h +++ b/libnymea-app/libnymea-app-core.h @@ -120,6 +120,12 @@ #include "types/ioconnection.h" #include "types/ioconnections.h" #include "types/ioconnectionwatcher.h" +#include "zigbee/zigbeemanager.h" +#include "zigbee/zigbeeadapter.h" +#include "zigbee/zigbeeadapters.h" +#include "zigbee/zigbeeadaptersproxy.h" +#include "zigbee/zigbeenetwork.h" +#include "zigbee/zigbeenetworks.h" #include @@ -297,6 +303,13 @@ void registerQmlTypes() { qmlRegisterUncreatableType(uri, 1, 0, "Repository", "Get it from Repositories"); qmlRegisterType(uri, 1, 0, "PackagesFilterModel"); + qmlRegisterType(uri, 1, 0, "ZigbeeManager"); + qmlRegisterUncreatableType(uri, 1, 0, "ZigbeeAdapter", "Get it from the ZigbeeAdapters"); + qmlRegisterUncreatableType(uri, 1, 0, "ZigbeeAdapters", "Get it from ZigbeeManager"); + qmlRegisterType(uri, 1, 0, "ZigbeeAdaptersProxy"); + qmlRegisterUncreatableType(uri, 1, 0, "ZigbeeNetwork", "Get it from the ZigbeeManager"); + qmlRegisterUncreatableType(uri, 1, 0, "ZigbeeNetworks", "Get it from the ZigbeeManager"); + qmlRegisterType(uri, 1, 0, "NetworkManager"); qmlRegisterUncreatableType(uri, 1, 0, "NetworkDevices", "Get it from NetworkManager"); qmlRegisterUncreatableType(uri, 1, 0, "WiredNetworkDevices", "Get it from NetworkManager"); diff --git a/libnymea-app/libnymea-app.pro b/libnymea-app/libnymea-app.pro index 273e7d6b..b0cdc5b9 100644 --- a/libnymea-app/libnymea-app.pro +++ b/libnymea-app/libnymea-app.pro @@ -160,6 +160,13 @@ SOURCES += \ models/devicemodel.cpp \ system/systemcontroller.cpp \ thinggroup.cpp \ + zigbee/zigbeeadapters.cpp \ + zigbee/zigbeeadaptersproxy.cpp \ + zigbee/zigbeemanager.cpp \ + zigbee/zigbeeadapter.cpp \ + zigbee/zigbeenetwork.cpp \ + zigbee/zigbeenetworks.cpp + HEADERS += \ @@ -299,6 +306,12 @@ HEADERS += \ models/devicemodel.h \ system/systemcontroller.h \ thinggroup.h \ + zigbee/zigbeeadapters.h \ + zigbee/zigbeeadaptersproxy.h \ + zigbee/zigbeemanager.h \ + zigbee/zigbeeadapter.h \ + zigbee/zigbeenetwork.h \ + zigbee/zigbeenetworks.h ubports: { DEFINES += UBPORTS diff --git a/libnymea-app/zigbee/zigbeeadapter.cpp b/libnymea-app/zigbee/zigbeeadapter.cpp new file mode 100644 index 00000000..7a4f3741 --- /dev/null +++ b/libnymea-app/zigbee/zigbeeadapter.cpp @@ -0,0 +1,136 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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" + +ZigbeeAdapter::ZigbeeAdapter(QObject *parent) : QObject(parent) +{ + +} + +QString ZigbeeAdapter::name() const +{ + return m_name; +} + +void ZigbeeAdapter::setName(const QString &name) +{ + m_name = name; + emit nameChanged(); +} + +QString ZigbeeAdapter::description() const +{ + return m_description; +} + +void ZigbeeAdapter::setDescription(const QString &description) +{ + m_description = description; + emit descriptionChanged(); +} + +QString ZigbeeAdapter::serialPort() const +{ + return m_serialPort; +} + +void ZigbeeAdapter::setSerialPort(const QString &serialPort) +{ + m_serialPort = serialPort; + emit serialPortChanged(); +} + +QString ZigbeeAdapter::serialNumber() const +{ + return m_serialNumber; +} + +void ZigbeeAdapter::setSerialNumber(const QString &serialNumber) +{ + m_serialNumber = serialNumber; + emit serialNumberChanged(); +} + +bool ZigbeeAdapter::hardwareRecognized() const +{ + return m_hardwareRecognized; +} + +void ZigbeeAdapter::setHardwareRecognized(bool hardwareRecognized) +{ + m_hardwareRecognized = hardwareRecognized; + emit hardwareRecognizedChanged(); +} + +QString ZigbeeAdapter::backend() const +{ + return m_backend; +} + +void ZigbeeAdapter::setBackend(const QString &backend) +{ + m_backend = backend; + emit backendChanged(); +} + +qint32 ZigbeeAdapter::baudRate() const +{ + return m_baudRate; +} + +void ZigbeeAdapter::setBaudRate(qint32 baudRate) +{ + m_baudRate = baudRate; + emit baudRateChanged(); +} + +bool ZigbeeAdapter::operator==(const ZigbeeAdapter &other) const +{ + return m_serialPort == other.serialPort() + && m_name == other.name() + && m_description == other.description() + && m_hardwareRecognized == other.hardwareRecognized() + && m_backend == other.backend() + && m_baudRate == other.baudRate(); +} + +QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter) +{ + debug.nospace() << "ZigbeeAdapter(" << adapter.name() << " - " << adapter.description(); + debug.nospace() << ", " << adapter.serialPort(); + if (adapter.hardwareRecognized()) { + debug.nospace() << " Hardware recognized: " << adapter.backend(); + debug.nospace() << ", " << adapter.baudRate(); + } + + debug.nospace() << ")"; + return debug.space(); +} diff --git a/libnymea-app/zigbee/zigbeeadapter.h b/libnymea-app/zigbee/zigbeeadapter.h new file mode 100644 index 00000000..7bf1ab28 --- /dev/null +++ b/libnymea-app/zigbee/zigbeeadapter.h @@ -0,0 +1,95 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 + +class ZigbeeAdapter : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged) + Q_PROPERTY(QString serialPort READ serialPort WRITE setSerialPort NOTIFY serialPortChanged) + Q_PROPERTY(QString serialNumber READ serialNumber WRITE setSerialNumber NOTIFY serialNumberChanged) + Q_PROPERTY(bool hardwareRecognized READ hardwareRecognized WRITE setHardwareRecognized NOTIFY hardwareRecognizedChanged) + Q_PROPERTY(QString backend READ backend WRITE setBackend NOTIFY backendChanged) + Q_PROPERTY(qint32 baudRate READ baudRate WRITE setBaudRate NOTIFY baudRateChanged) + +public: + explicit ZigbeeAdapter(QObject *parent = nullptr); + + QString name() const; + void setName(const QString &name); + + QString description() const; + void setDescription(const QString &description); + + QString serialPort() const; + void setSerialPort(const QString &serialPort); + + QString serialNumber() const; + void setSerialNumber(const QString &serialNumber); + + bool hardwareRecognized() const; + void setHardwareRecognized(bool hardwareRecognized); + + QString backend() const; + void setBackend(const QString &backend); + + qint32 baudRate() const; + void setBaudRate(qint32 baudRate); + + bool operator==(const ZigbeeAdapter &other) const; + +private: + QString m_name; + QString m_description; + QString m_serialPort; + QString m_serialNumber; + bool m_hardwareRecognized = false; + QString m_backend; + qint32 m_baudRate = 38400; + +signals: + void nameChanged(); + void descriptionChanged(); + void serialPortChanged(); + void serialNumberChanged(); + void hardwareRecognizedChanged(); + void backendChanged(); + void baudRateChanged(); +}; + +QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter); + +#endif // ZIGBEEADAPTER_H diff --git a/libnymea-app/zigbee/zigbeeadapters.cpp b/libnymea-app/zigbee/zigbeeadapters.cpp new file mode 100644 index 00000000..6e3a9d53 --- /dev/null +++ b/libnymea-app/zigbee/zigbeeadapters.cpp @@ -0,0 +1,145 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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" + +ZigbeeAdapters::ZigbeeAdapters(QObject *parent) : QAbstractListModel(parent) +{ + +} + +int ZigbeeAdapters::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_adapters.count(); +} + +QVariant ZigbeeAdapters::data(const QModelIndex &index, int role) const +{ + switch (role) { + case RoleName: + return m_adapters.at(index.row())->name(); + case RoleDescription: + return m_adapters.at(index.row())->description(); + case RoleSerialPort: + return m_adapters.at(index.row())->serialPort(); + case RoleHardwareRecognized: + return m_adapters.at(index.row())->hardwareRecognized(); + case RoleBackend: + return m_adapters.at(index.row())->backend(); + case RoleBaudRate: + return m_adapters.at(index.row())->baudRate(); + } + return QVariant(); +} + +QHash ZigbeeAdapters::roleNames() const +{ + QHash roles; + roles.insert(RoleName, "name"); + roles.insert(RoleDescription, "description"); + roles.insert(RoleSerialPort, "serialPort"); + roles.insert(RoleHardwareRecognized, "hardwareRecognized"); + roles.insert(RoleBackend, "backend"); + roles.insert(RoleBaudRate, "baudRate"); + return roles; +} + +void ZigbeeAdapters::addAdapter(ZigbeeAdapter *adapter) +{ + adapter->setParent(this); + + beginInsertRows(QModelIndex(), m_adapters.count(), m_adapters.count()); + m_adapters.append(adapter); + + connect(adapter, &ZigbeeAdapter::nameChanged, this, [this, adapter]() { + QModelIndex idx = index(m_adapters.indexOf(adapter), 0); + emit dataChanged(idx, idx, {RoleName}); + }); + + connect(adapter, &ZigbeeAdapter::descriptionChanged, this, [this, adapter]() { + QModelIndex idx = index(m_adapters.indexOf(adapter), 0); + emit dataChanged(idx, idx, {RoleDescription}); + }); + + connect(adapter, &ZigbeeAdapter::serialPortChanged, this, [this, adapter]() { + QModelIndex idx = index(m_adapters.indexOf(adapter), 0); + emit dataChanged(idx, idx, {RoleSerialPort}); + }); + + connect(adapter, &ZigbeeAdapter::hardwareRecognizedChanged, this, [this, adapter]() { + QModelIndex idx = index(m_adapters.indexOf(adapter), 0); + emit dataChanged(idx, idx, {RoleHardwareRecognized}); + }); + + connect(adapter, &ZigbeeAdapter::backendChanged, this, [this, adapter]() { + QModelIndex idx = index(m_adapters.indexOf(adapter), 0); + emit dataChanged(idx, idx, {RoleBackend}); + }); + + connect(adapter, &ZigbeeAdapter::baudRateChanged, this, [this, adapter]() { + QModelIndex idx = index(m_adapters.indexOf(adapter), 0); + emit dataChanged(idx, idx, {RoleBaudRate}); + }); + + endInsertRows(); + + emit countChanged(); +} + +void ZigbeeAdapters::removeAdapter(const QString &serialPort) +{ + for (int i = 0; i < m_adapters.count(); i++) { + if (m_adapters.at(i)->serialPort() == serialPort) { + beginRemoveRows(QModelIndex(), i, i); + m_adapters.takeAt(i)->deleteLater(); + endRemoveRows(); + return; + } + } +} + +void ZigbeeAdapters::clear() +{ + beginResetModel(); + qDeleteAll(m_adapters); + m_adapters.clear(); + endResetModel(); + emit countChanged(); +} + +ZigbeeAdapter *ZigbeeAdapters::get(int index) const +{ + if (index < 0 || index >= m_adapters.count()) { + return nullptr; + } + + return m_adapters.at(index); +} diff --git a/libnymea-app/zigbee/zigbeeadapters.h b/libnymea-app/zigbee/zigbeeadapters.h new file mode 100644 index 00000000..a022f754 --- /dev/null +++ b/libnymea-app/zigbee/zigbeeadapters.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 ZIGBEEADAPTERS_H +#define ZIGBEEADAPTERS_H + +#include +#include + +#include "zigbeeadapter.h" + +class ZigbeeAdapters : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + +public: + enum Roles { + RoleName, + RoleDescription, + RoleSerialPort, + RoleHardwareRecognized, + RoleBackend, + RoleBaudRate + }; + Q_ENUM(Roles) + + explicit ZigbeeAdapters(QObject *parent = nullptr); + virtual ~ZigbeeAdapters() override = default; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + + void addAdapter(ZigbeeAdapter *adapter); + void removeAdapter(const QString &serialPort); + + void clear(); + + Q_INVOKABLE virtual ZigbeeAdapter *get(int index) const; + +signals: + void countChanged(); + +protected: + QList m_adapters; + +}; + +#endif // ZIGBEEADAPTERS_H diff --git a/libnymea-app/zigbee/zigbeeadaptersproxy.cpp b/libnymea-app/zigbee/zigbeeadaptersproxy.cpp new file mode 100644 index 00000000..8786a873 --- /dev/null +++ b/libnymea-app/zigbee/zigbeeadaptersproxy.cpp @@ -0,0 +1,126 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 "zigbeeadaptersproxy.h" + +#include "zigbeemanager.h" +#include "zigbeeadapters.h" +#include "zigbeenetworks.h" + +ZigbeeAdaptersProxy::ZigbeeAdaptersProxy(QObject *parent) : QSortFilterProxyModel(parent) +{ + +} + +ZigbeeManager *ZigbeeAdaptersProxy::manager() const +{ + return m_manager; +} + +void ZigbeeAdaptersProxy::setManager(ZigbeeManager *manager) +{ + if (m_manager != manager) { + m_manager = manager; + connect(m_manager->adapters(), &ZigbeeAdapters::countChanged, this, [this](){ + emit countChanged(); + }); + connect(m_manager->networks(), &ZigbeeNetworks::countChanged, this, [this]() { + invalidateFilter(); + }); + setSourceModel(m_manager->adapters()); + setSortRole(ZigbeeAdapters::RoleSerialPort); + sort(0, Qt::DescendingOrder); + invalidateFilter(); + emit countChanged(); + } +} + +ZigbeeAdaptersProxy::HardwareFilter ZigbeeAdaptersProxy::hardwareFilter() const +{ + return m_hardwareFilter; +} + +void ZigbeeAdaptersProxy::setHardwareFilter(ZigbeeAdaptersProxy::HardwareFilter hardwareFilter) +{ + if (m_hardwareFilter != hardwareFilter) { + m_hardwareFilter = hardwareFilter; + emit hardwareFilterChanged(m_hardwareFilter); + + invalidateFilter(); + emit countChanged(); + } +} + +bool ZigbeeAdaptersProxy::onlyUnused() const +{ + return m_onlyUnused; +} + +void ZigbeeAdaptersProxy::setOnlyUnused(bool onlyUnused) +{ + if (m_onlyUnused != onlyUnused) { + m_onlyUnused = onlyUnused; + emit onlyUnusedChanged(); + + invalidateFilter(); + emit countChanged(); + } +} + +ZigbeeAdapter *ZigbeeAdaptersProxy::get(int index) const +{ + if (index >= 0 && index < m_manager->adapters()->rowCount()) { + return m_manager->adapters()->get(mapToSource(this->index(index, 0)).row()); + } + return nullptr; +} + +bool ZigbeeAdaptersProxy::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + Q_UNUSED(source_parent) + + ZigbeeAdapter *adapter = m_manager->adapters()->get(source_row); + + if (m_hardwareFilter == HardwareFilterRecognized && !adapter->hardwareRecognized()) { + return false; + } + + if (m_hardwareFilter == HardwareFilterUnrecognized && adapter->hardwareRecognized()) { + return false; + } + + if (m_onlyUnused) { + if (m_manager->networks()->findBySerialPort(adapter->serialPort()) != nullptr) { + return false; + } + } + + return true; +} diff --git a/libnymea-app/zigbee/zigbeeadaptersproxy.h b/libnymea-app/zigbee/zigbeeadaptersproxy.h new file mode 100644 index 00000000..7005d7eb --- /dev/null +++ b/libnymea-app/zigbee/zigbeeadaptersproxy.h @@ -0,0 +1,88 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 ZIGBEEADAPTERSPROXY_H +#define ZIGBEEADAPTERSPROXY_H + +#include +#include + +class ZigbeeAdapter; +class ZigbeeManager; + +class ZigbeeAdaptersProxy : public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + + // Required + Q_PROPERTY(ZigbeeManager* manager READ manager WRITE setManager NOTIFY managerChanged) + + // Optional filtering + Q_PROPERTY(ZigbeeAdaptersProxy::HardwareFilter hardwareFilter READ hardwareFilter WRITE setHardwareFilter NOTIFY hardwareFilterChanged) + Q_PROPERTY(bool onlyUnused READ onlyUnused WRITE setOnlyUnused NOTIFY onlyUnusedChanged) + +public: + enum HardwareFilter { + HardwareFilterNone, + HardwareFilterRecognized, + HardwareFilterUnrecognized + }; + Q_ENUM(HardwareFilter) + + explicit ZigbeeAdaptersProxy(QObject *parent = nullptr); + + ZigbeeManager *manager() const; + void setManager(ZigbeeManager *manager); + + HardwareFilter hardwareFilter() const; + void setHardwareFilter(HardwareFilter hardwareFilter); + + bool onlyUnused() const; + void setOnlyUnused(bool onlyUnused); + + Q_INVOKABLE ZigbeeAdapter* get(int index) const; + +protected: + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; + +signals: + void countChanged(); + void managerChanged(); + void hardwareFilterChanged(HardwareFilter hardwareFilter); + void onlyUnusedChanged(); + +private: + ZigbeeManager *m_manager = nullptr; + HardwareFilter m_hardwareFilter = HardwareFilterNone; + bool m_onlyUnused = false; +}; + +#endif // ZIGBEEADAPTERSPROXY_H diff --git a/libnymea-app/zigbee/zigbeemanager.cpp b/libnymea-app/zigbee/zigbeemanager.cpp new file mode 100644 index 00000000..a07d5ebb --- /dev/null +++ b/libnymea-app/zigbee/zigbeemanager.cpp @@ -0,0 +1,285 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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" + +#include "engine.h" +#include "jsonrpc/jsonrpcclient.h" +#include "zigbee/zigbeeadapter.h" +#include "zigbee/zigbeeadapters.h" +#include "zigbee/zigbeenetwork.h" +#include "zigbee/zigbeenetworks.h" + +#include + +ZigbeeManager::ZigbeeManager(QObject *parent) : + JsonHandler(parent), + m_adapters(new ZigbeeAdapters(this)), + m_networks(new ZigbeeNetworks(this)) +{ + +} + +ZigbeeManager::~ZigbeeManager() +{ + if (m_engine) { + m_engine->jsonRpcClient()->unregisterNotificationHandler(this); + } +} + +QString ZigbeeManager::nameSpace() const +{ + return "Zigbee"; +} + +void ZigbeeManager::setEngine(Engine *engine) +{ + if (m_engine != engine) { + + if (m_engine) { + m_engine->jsonRpcClient()->unregisterNotificationHandler(this); + } + + m_engine = engine; + emit engineChanged(); + init(); + } +} + +Engine *ZigbeeManager::engine() const +{ + return m_engine; +} + +QStringList ZigbeeManager::availableBackends() const +{ + return m_availableBackends; +} + +ZigbeeAdapters *ZigbeeManager::adapters() const +{ + return m_adapters; +} + +ZigbeeNetworks *ZigbeeManager::networks() const +{ + return m_networks; +} + +int ZigbeeManager::addNetwork(const QString &serialPort, uint baudRate, const QString &backend) +{ + QVariantMap params; + params.insert("serialPort", serialPort); + params.insert("baudRate", baudRate); + params.insert("backend", backend); + + qDebug() << "Add zigbee network" << params; + return m_engine->jsonRpcClient()->sendCommand("Zigbee.AddNetwork", params, this, "addNetworkResponse"); +} + +void ZigbeeManager::removeNetwork(const QUuid &networkUuid) +{ + QVariantMap params; + params.insert("networkUuid", networkUuid); + qDebug() << "Remove zigbee network" << params; + m_engine->jsonRpcClient()->sendCommand("Zigbee.RemoveNetwork", params, this, "removeNetworkResponse"); +} + +void ZigbeeManager::setPermitJoin(const QUuid &networkUuid, uint duration) +{ + QVariantMap params; + params.insert("networkUuid", networkUuid); + params.insert("duration", duration); + m_engine->jsonRpcClient()->sendCommand("Zigbee.SetPermitJoin", params, this, "setPermitJoinResponse"); +} + +void ZigbeeManager::factoryResetNetwork(const QUuid &networkUuid) +{ + QVariantMap params; + params.insert("networkUuid", networkUuid); + m_engine->jsonRpcClient()->sendCommand("Zigbee.FactoryResetNetwork", params, this, "factoryResetNetworkResponse"); +} + +void ZigbeeManager::init() +{ + m_adapters->clear(); + m_networks->clear(); + m_availableBackends.clear(); + + m_engine->jsonRpcClient()->registerNotificationHandler(this, "notificationReceived"); + + m_engine->jsonRpcClient()->sendCommand("Zigbee.GetAvailableBackends", this, "getAvailableBackendsResponse"); + m_engine->jsonRpcClient()->sendCommand("Zigbee.GetAdapters", this, "getAdaptersResponse"); + m_engine->jsonRpcClient()->sendCommand("Zigbee.GetNetworks", this, "getNetworksResponse"); +} + +void ZigbeeManager::getAvailableBackendsResponse(int commandId, const QVariantMap ¶ms) +{ + qDebug() << "Zigbee get available backends response" << commandId << params; + m_availableBackends.clear(); + foreach (const QVariant &backendVariant, params.value("backends").toList()) { + m_availableBackends << backendVariant.toString(); + } + emit availableBackendsChanged(); +} + +void ZigbeeManager::getAdaptersResponse(int commandId, const QVariantMap ¶ms) +{ + qDebug() << "Zigbee get adapters response" << commandId << params; + m_adapters->clear(); + foreach (const QVariant &adapterVariant, params.value("adapters").toList()) { + QVariantMap adapterMap = adapterVariant.toMap(); + ZigbeeAdapter *adapter = unpackAdapter(adapterMap); + qDebug() << "Zigbee adapter added" << adapter->description() << adapter->serialPort() << adapter->hardwareRecognized(); + m_adapters->addAdapter(adapter); + } + +// ZigbeeAdapter *fakeAdapter = new ZigbeeAdapter(); +// fakeAdapter->setSerialPort("/dev/fake"); +// fakeAdapter->setBackend("Fake"); +// fakeAdapter->setBaudRate(9600); +// fakeAdapter->setDescription("Fake adapter"); +// fakeAdapter->setHardwareRecognized(true); +// fakeAdapter->setName("Fake"); +// m_adapters->addAdapter(fakeAdapter); +} + +void ZigbeeManager::getNetworksResponse(int commandId, const QVariantMap ¶ms) +{ + qDebug() << "Zigbee get networks response" << commandId << params; + m_networks->clear(); + foreach (const QVariant &networkVariant, params.value("zigbeeNetworks").toList()) { + QVariantMap networkMap = networkVariant.toMap(); + ZigbeeNetwork *network = unpackNetwork(networkMap); + qDebug() << "Zigbee network added" << network->networkUuid().toString() << network->serialPort() << network->macAddress(); + m_networks->addNetwork(network); + } +} + +void ZigbeeManager::addNetworkResponse(int commandId, const QVariantMap ¶ms) +{ + qDebug() << "Zigbee add network response" << commandId << params; + emit addNetworkReply(commandId, params.value("zigbeeError").toString(), params.value("networkUuid").toUuid()); +} + +void ZigbeeManager::removeNetworkResponse(int commandId, const QVariantMap ¶ms) +{ + qDebug() << "Zigbee remove network response" << commandId << params; +} + +void ZigbeeManager::setPermitJoinResponse(int commandId, const QVariantMap ¶ms) +{ + qDebug() << "Zigbee set permit join network response" << commandId << params; +} + +void ZigbeeManager::factoryResetNetworkResponse(int commandId, const QVariantMap ¶ms) +{ + qDebug() << "Zigbee factory reset network response" << commandId << params; +} + +void ZigbeeManager::notificationReceived(const QVariantMap ¬ification) +{ + QString notificationString = notification.value("notification").toString(); + if (notificationString == "Zigbee.AdapterAdded") { + QVariantMap adapterMap = notification.value("params").toMap().value("adapter").toMap(); + m_adapters->addAdapter(unpackAdapter(adapterMap)); + return; + } + + if (notificationString == "Zigbee.AdapterRemoved") { + QVariantMap adapterMap = notification.value("params").toMap().value("adapter").toMap(); + m_adapters->removeAdapter(adapterMap.value("serialPort").toString()); + return; + } + + if (notificationString == "Zigbee.NetworkAdded") { + QVariantMap networkMap = notification.value("params").toMap().value("zigbeeNetwork").toMap(); + m_networks->addNetwork(unpackNetwork(networkMap)); + return; + } + + if (notificationString == "Zigbee.NetworkRemoved") { + QUuid networkUuid = notification.value("params").toMap().value("networkUuid").toUuid(); + m_networks->removeNetwork(networkUuid); + return; + } + + if (notificationString == "Zigbee.NetworkChanged") { + QVariantMap networkMap = notification.value("params").toMap().value("zigbeeNetwork").toMap(); + QUuid networkUuid = networkMap.value("networkUuid").toUuid(); + ZigbeeNetwork *network = m_networks->getNetwork(networkUuid); + if (!network) { + qWarning() << "Could not find network for changed notification"; + return; + } + fillNetworkData(network, networkMap); + return; + } + + qDebug() << "Unhandled Zigbee notification" << notificationString << notification; +} + +ZigbeeAdapter *ZigbeeManager::unpackAdapter(const QVariantMap &adapterMap) +{ + ZigbeeAdapter *adapter = new ZigbeeAdapter(m_adapters); + adapter->setName(adapterMap.value("name").toString()); + adapter->setDescription(adapterMap.value("description").toString()); + adapter->setSerialPort(adapterMap.value("serialPort").toString()); + adapter->setSerialNumber(adapterMap.value("serialNumber").toString()); + adapter->setHardwareRecognized(adapterMap.value("hardwareRecognized").toBool()); + adapter->setBackend(adapterMap.value("backend").toString()); + adapter->setBaudRate(adapterMap.value("baudRate").toUInt()); + return adapter; +} + +ZigbeeNetwork *ZigbeeManager::unpackNetwork(const QVariantMap &networkMap) +{ + ZigbeeNetwork *network = new ZigbeeNetwork(m_networks); + fillNetworkData(network, networkMap); + return network; +} + +void ZigbeeManager::fillNetworkData(ZigbeeNetwork *network, const QVariantMap &networkMap) +{ + network->setNetworkUuid(networkMap.value("networkUuid").toUuid()); + network->setSerialPort(networkMap.value("serialPort").toString()); + network->setBaudRate(networkMap.value("baudRate").toUInt()); + network->setMacAddress(networkMap.value("macAddress").toString()); + network->setFirmwareVersion(networkMap.value("firmwareVersion").toString()); + network->setPanId(networkMap.value("panId").toUInt()); + network->setChannel(networkMap.value("channel").toUInt()); + network->setChannelMask(networkMap.value("channelMask").toUInt()); + network->setPermitJoiningEnabled(networkMap.value("permitJoiningEnabled").toBool()); + network->setPermitJoiningDuration(networkMap.value("permitJoiningDuration").toUInt()); + network->setPermitJoiningRemaining(networkMap.value("permitJoiningRemaining").toUInt()); + network->setBackend(networkMap.value("backend").toString()); + network->setNetworkState(ZigbeeNetwork::stringToZigbeeNetworkState(networkMap.value("networkState").toString())); +} + diff --git a/libnymea-app/zigbee/zigbeemanager.h b/libnymea-app/zigbee/zigbeemanager.h new file mode 100644 index 00000000..abe55811 --- /dev/null +++ b/libnymea-app/zigbee/zigbeemanager.h @@ -0,0 +1,102 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 "zigbeeadapter.h" +#include "jsonrpc/jsonhandler.h" + +class JsonRpcClient; +class ZigbeeAdapters; +class ZigbeeNetwork; +class ZigbeeNetworks; +class Engine; + +class ZigbeeManager : public JsonHandler +{ + Q_OBJECT + Q_PROPERTY(Engine* engine READ engine WRITE setEngine NOTIFY engineChanged) + + Q_PROPERTY(QStringList availableBackends READ availableBackends NOTIFY availableBackendsChanged) + Q_PROPERTY(ZigbeeAdapters *adapters READ adapters CONSTANT) + Q_PROPERTY(ZigbeeNetworks *networks READ networks CONSTANT) + +public: + explicit ZigbeeManager(QObject *parent = nullptr); + ~ZigbeeManager(); + + QString nameSpace() const override; + + void setEngine(Engine *engine); + Engine *engine() const; + + QStringList availableBackends() const; + ZigbeeAdapters *adapters() const; + ZigbeeNetworks *networks() const; + + Q_INVOKABLE int addNetwork(const QString &serialPort, uint baudRate, const QString &backend); + Q_INVOKABLE void removeNetwork(const QUuid &networkUuid); + Q_INVOKABLE void setPermitJoin(const QUuid &networkUuid, uint duration = 120); + Q_INVOKABLE void factoryResetNetwork(const QUuid &networkUuid); + +signals: + void engineChanged(); + void availableBackendsChanged(); + void addNetworkReply(int commandId, const QString &error, const QUuid &networkUuid); + +private: + void init(); + + Q_INVOKABLE void getAvailableBackendsResponse(int commandId, const QVariantMap ¶ms); + Q_INVOKABLE void getAdaptersResponse(int commandId, const QVariantMap ¶ms); + Q_INVOKABLE void getNetworksResponse(int commandId, const QVariantMap ¶ms); + + Q_INVOKABLE void addNetworkResponse(int commandId, const QVariantMap ¶ms); + Q_INVOKABLE void removeNetworkResponse(int commandId, const QVariantMap ¶ms); + Q_INVOKABLE void setPermitJoinResponse(int commandId, const QVariantMap ¶ms); + Q_INVOKABLE void factoryResetNetworkResponse(int commandId, const QVariantMap ¶ms); + + Q_INVOKABLE void notificationReceived(const QVariantMap ¬ification); + +private: + Engine* m_engine = nullptr; + QStringList m_availableBackends; + ZigbeeAdapters *m_adapters = nullptr; + ZigbeeNetworks *m_networks = nullptr; + + ZigbeeAdapter *unpackAdapter(const QVariantMap &adapterMap); + ZigbeeNetwork *unpackNetwork(const QVariantMap &networkMap); + void fillNetworkData(ZigbeeNetwork *network, const QVariantMap &networkMap); + +}; + +#endif // ZIGBEEMANAGER_H diff --git a/libnymea-app/zigbee/zigbeenetwork.cpp b/libnymea-app/zigbee/zigbeenetwork.cpp new file mode 100644 index 00000000..22e0b6c4 --- /dev/null +++ b/libnymea-app/zigbee/zigbeenetwork.cpp @@ -0,0 +1,267 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 "zigbeenetwork.h" + +ZigbeeNetwork::ZigbeeNetwork(QObject *parent) : QObject(parent) +{ + m_permitJoinTimer = new QTimer(this); + m_permitJoinTimer->setInterval(1000); + m_permitJoinTimer->setSingleShot(true); + connect(m_permitJoinTimer, &QTimer::timeout, this, [this](){ + + setPermitJoiningRemaining(m_permitJoiningRemaining - 1); + if (m_permitJoiningRemaining <= 0) { + m_permitJoinTimer->stop(); + } + }); +} + +QUuid ZigbeeNetwork::networkUuid() const +{ + return m_networkUuid; +} + +void ZigbeeNetwork::setNetworkUuid(const QUuid &networkUuid) +{ + if (m_networkUuid == networkUuid) + return; + + m_networkUuid = networkUuid; + emit networkUuidChanged(); +} + +bool ZigbeeNetwork::enabled() const +{ + return m_enabled; +} + +void ZigbeeNetwork::setEnabled(bool enabled) +{ + if (m_enabled == enabled) + return; + + m_enabled = enabled; + emit enabledChanged(); +} + +QString ZigbeeNetwork::serialPort() const +{ + return m_serialPort; +} + +void ZigbeeNetwork::setSerialPort(const QString &serialPort) +{ + if (m_serialPort == serialPort) + return; + + m_serialPort = serialPort; + emit serialPortChanged(); +} + +uint ZigbeeNetwork::baudRate() const +{ + return m_baudRate; +} + +void ZigbeeNetwork::setBaudRate(uint baudRate) +{ + if (m_baudRate == baudRate) + return; + + m_baudRate = baudRate; + emit baudRateChanged(); +} + +QString ZigbeeNetwork::macAddress() const +{ + return m_macAddress; +} + +void ZigbeeNetwork::setMacAddress(const QString &macAddress) +{ + if (m_macAddress == macAddress) + return; + + m_macAddress = macAddress; + emit macAddressChanged(); +} + +QString ZigbeeNetwork::firmwareVersion() const +{ + return m_firmwareVersion; +} + +void ZigbeeNetwork::setFirmwareVersion(const QString &firmwareVersion) +{ + if (m_firmwareVersion == firmwareVersion) + return; + + m_firmwareVersion = firmwareVersion; + emit firmwareVersionChanged(); +} + +uint ZigbeeNetwork::panId() const +{ + return m_panId; +} + +void ZigbeeNetwork::setPanId(uint panId) +{ + if (m_panId == panId) + return; + + m_panId = panId; + emit panIdChanged(); +} + +uint ZigbeeNetwork::channel() const +{ + return m_channel; +} + +void ZigbeeNetwork::setChannel(uint channel) +{ + if (m_channel == channel) + return; + + m_channel = channel; + emit channelChanged(); +} + +uint ZigbeeNetwork::channelMask() const +{ + return m_channelMask; +} + +void ZigbeeNetwork::setChannelMask(uint channelMask) +{ + if (m_channelMask == channelMask) + return; + + m_channelMask = channelMask; + emit channelMaskChanged(); +} + +bool ZigbeeNetwork::permitJoiningEnabled() const +{ + return m_permitJoiningEnabled; +} + +void ZigbeeNetwork::setPermitJoiningEnabled(bool permitJoiningEnabled) +{ + if (m_permitJoiningEnabled == permitJoiningEnabled) + return; + + m_permitJoiningEnabled = permitJoiningEnabled; + emit permitJoiningEnabledChanged(); +} + +uint ZigbeeNetwork::permitJoiningDuration() const +{ + return m_permitJoiningDuration; +} + +void ZigbeeNetwork::setPermitJoiningDuration(uint permitJoiningDuration) +{ + if (m_permitJoiningDuration == permitJoiningDuration) + return; + + m_permitJoiningDuration = permitJoiningDuration; + emit permitJoiningDurationChanged(); +} + +uint ZigbeeNetwork::permitJoiningRemaining() const +{ + return m_permitJoiningRemaining; +} + +void ZigbeeNetwork::setPermitJoiningRemaining(uint permitJoiningRemaining) +{ + if (m_permitJoiningRemaining == permitJoiningRemaining) + return; + + m_permitJoiningRemaining = permitJoiningRemaining; + emit permitJoiningRemainingChanged(); + + if (m_permitJoinTimer->isActive()) + m_permitJoinTimer->stop(); + + if (m_permitJoiningRemaining != 0) { + m_permitJoinTimer->start(); + } +} + +QString ZigbeeNetwork::backend() const +{ + return m_backend; +} + +void ZigbeeNetwork::setBackend(const QString &backend) +{ + if (m_backend == backend) + return; + + m_backend = backend; + emit backendChanged(); +} + +ZigbeeNetwork::ZigbeeNetworkState ZigbeeNetwork::networkState() const +{ + return m_networkState; +} + +void ZigbeeNetwork::setNetworkState(ZigbeeNetwork::ZigbeeNetworkState networkState) +{ + if (m_networkState == networkState) + return; + + m_networkState = networkState; + emit networkStateChanged(); +} + +ZigbeeNetwork::ZigbeeNetworkState ZigbeeNetwork::stringToZigbeeNetworkState(const QString &networkStateString) +{ + if (networkStateString == "ZigbeeNetworkStateOffline") { + return ZigbeeNetworkStateOffline; + } else if (networkStateString == "ZigbeeNetworkStateStarting") { + return ZigbeeNetworkStateStarting; + } else if (networkStateString == "ZigbeeNetworkStateUpdating") { + return ZigbeeNetworkStateUpdating; + } else if (networkStateString == "ZigbeeNetworkStateOnline") { + return ZigbeeNetworkStateOnline; + } else if (networkStateString == "ZigbeeNetworkStateError") { + return ZigbeeNetworkStateError; + } else { + return ZigbeeNetworkStateError; + } +} + + diff --git a/libnymea-app/zigbee/zigbeenetwork.h b/libnymea-app/zigbee/zigbeenetwork.h new file mode 100644 index 00000000..6cfd86dc --- /dev/null +++ b/libnymea-app/zigbee/zigbeenetwork.h @@ -0,0 +1,151 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 ZIGBEENETWORK_H +#define ZIGBEENETWORK_H + +#include +#include +#include + +#include "zigbeeadapter.h" + +class ZigbeeNetwork : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUuid networkUuid READ networkUuid NOTIFY networkUuidChanged) + Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged) + Q_PROPERTY(QString serialPort READ serialPort NOTIFY serialPortChanged) + Q_PROPERTY(uint baudRate READ baudRate NOTIFY baudRateChanged) + Q_PROPERTY(QString macAddress READ macAddress NOTIFY macAddressChanged) + Q_PROPERTY(QString firmwareVersion READ firmwareVersion NOTIFY firmwareVersionChanged) + Q_PROPERTY(uint panId READ panId NOTIFY panIdChanged) + Q_PROPERTY(uint channel READ channel NOTIFY channelChanged) + Q_PROPERTY(uint channelMask READ channelMask NOTIFY channelMaskChanged) + Q_PROPERTY(bool permitJoiningEnabled READ permitJoiningEnabled NOTIFY permitJoiningEnabledChanged) + Q_PROPERTY(uint permitJoiningDuration READ permitJoiningDuration NOTIFY permitJoiningDurationChanged) + Q_PROPERTY(uint permitJoiningRemaining READ permitJoiningRemaining NOTIFY permitJoiningRemainingChanged) + Q_PROPERTY(QString backend READ backend NOTIFY backendChanged) + Q_PROPERTY(ZigbeeNetworkState networkState READ networkState NOTIFY networkStateChanged) + + // Internal properties + +public: + enum ZigbeeNetworkState { + ZigbeeNetworkStateOffline, + ZigbeeNetworkStateStarting, + ZigbeeNetworkStateUpdating, + ZigbeeNetworkStateOnline, + ZigbeeNetworkStateError + }; + Q_ENUM(ZigbeeNetworkState) + + explicit ZigbeeNetwork(QObject *parent = nullptr); + + QUuid networkUuid() const; + void setNetworkUuid(const QUuid &networkUuid); + + bool enabled() const; + void setEnabled(bool enabled); + + QString serialPort() const; + void setSerialPort(const QString &serialPort); + + uint baudRate() const; + void setBaudRate(uint baudRate); + + QString macAddress() const; + void setMacAddress(const QString &macAddress); + + QString firmwareVersion() const; + void setFirmwareVersion(const QString &firmwareVersion); + + uint panId() const; + void setPanId(uint panId); + + uint channel() const; + void setChannel(uint channel); + + uint channelMask() const; + void setChannelMask(uint channelMask); + + bool permitJoiningEnabled() const; + void setPermitJoiningEnabled(bool permitJoiningEnabled); + + uint permitJoiningDuration() const; + void setPermitJoiningDuration(uint permitJoiningDuration); + + uint permitJoiningRemaining() const; + void setPermitJoiningRemaining(uint permitJoiningRemaining); + + QString backend() const; + void setBackend(const QString &backend); + + ZigbeeNetworkState networkState() const; + void setNetworkState(ZigbeeNetworkState networkState); + + static ZigbeeNetworkState stringToZigbeeNetworkState(const QString &networkStateString); + +signals: + void networkUuidChanged(); + void enabledChanged(); + void serialPortChanged(); + void baudRateChanged(); + void macAddressChanged(); + void firmwareVersionChanged(); + void panIdChanged(); + void channelChanged(); + void channelMaskChanged(); + void permitJoiningEnabledChanged(); + void permitJoiningDurationChanged(); + void permitJoiningRemainingChanged(); + void backendChanged(); + void networkStateChanged(); + +private: + QUuid m_networkUuid; + bool m_enabled; + QString m_serialPort; + uint m_baudRate; + QString m_macAddress; + QString m_firmwareVersion; + uint m_panId; + uint m_channel; + uint m_channelMask; + bool m_permitJoiningEnabled; + uint m_permitJoiningDuration; + uint m_permitJoiningRemaining; + QString m_backend; + ZigbeeNetworkState m_networkState; + + QTimer *m_permitJoinTimer = nullptr; +}; + +#endif // ZIGBEENETWORK_H diff --git a/libnymea-app/zigbee/zigbeenetworks.cpp b/libnymea-app/zigbee/zigbeenetworks.cpp new file mode 100644 index 00000000..dd2e08eb --- /dev/null +++ b/libnymea-app/zigbee/zigbeenetworks.cpp @@ -0,0 +1,222 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 "zigbeenetworks.h" + +ZigbeeNetworks::ZigbeeNetworks(QObject *parent) : QAbstractListModel(parent) +{ + +} + +int ZigbeeNetworks::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_networks.count(); +} + +QVariant ZigbeeNetworks::data(const QModelIndex &index, int role) const +{ + switch (role) { + case RoleUuid: + return m_networks.at(index.row())->networkUuid(); + case RoleSerialPort: + return m_networks.at(index.row())->serialPort(); + case RoleBaudRate: + return m_networks.at(index.row())->baudRate(); + case RoleMacAddress: + return m_networks.at(index.row())->macAddress(); + case RoleFirmwareVersion: + return m_networks.at(index.row())->firmwareVersion(); + case RolePanId: + return m_networks.at(index.row())->panId(); + case RoleChannel: + return m_networks.at(index.row())->channel(); + case RoleChannelMask: + return m_networks.at(index.row())->channelMask(); + case RolePermitJoiningEnabled: + return m_networks.at(index.row())->permitJoiningEnabled(); + case RolePermitJoiningDuration: + return m_networks.at(index.row())->permitJoiningDuration(); + case RolePermitJoiningRemaining: + return m_networks.at(index.row())->permitJoiningRemaining(); + case RoleBackend: + return m_networks.at(index.row())->backend(); + case RoleNetworkState: + return m_networks.at(index.row())->networkState(); + } + + return QVariant(); +} + +QHash ZigbeeNetworks::roleNames() const +{ + QHash roles; + roles.insert(RoleUuid, "networkUuid"); + roles.insert(RoleSerialPort, "serialPort"); + roles.insert(RoleBaudRate, "baudRate"); + roles.insert(RoleMacAddress, "macAddress"); + roles.insert(RoleFirmwareVersion, "firmwareVersion"); + roles.insert(RolePanId, "panId"); + roles.insert(RoleChannel, "channel"); + roles.insert(RoleChannelMask, "channelMask"); + roles.insert(RolePermitJoiningEnabled, "permitJoiningEnabled"); + roles.insert(RolePermitJoiningDuration, "permitJoiningDuration"); + roles.insert(RolePermitJoiningRemaining, "permitJoiningRemaining"); + roles.insert(RoleBackend, "backend"); + roles.insert(RoleNetworkState, "networkState"); + return roles; + +} + +void ZigbeeNetworks::addNetwork(ZigbeeNetwork *network) +{ + network->setParent(this); + beginInsertRows(QModelIndex(), m_networks.count(), m_networks.count()); + m_networks.append(network); + connect(network, &ZigbeeNetwork::networkUuidChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RoleUuid}); + }); + + connect(network, &ZigbeeNetwork::serialPortChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RoleSerialPort}); + }); + + connect(network, &ZigbeeNetwork::baudRateChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RoleBaudRate}); + }); + + connect(network, &ZigbeeNetwork::macAddressChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RoleMacAddress}); + }); + + connect(network, &ZigbeeNetwork::firmwareVersionChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RoleFirmwareVersion}); + }); + + connect(network, &ZigbeeNetwork::panIdChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RolePanId}); + }); + + connect(network, &ZigbeeNetwork::channelChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RoleChannel}); + }); + + connect(network, &ZigbeeNetwork::channelMaskChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RoleChannelMask}); + }); + + connect(network, &ZigbeeNetwork::permitJoiningEnabledChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RolePermitJoiningEnabled}); + }); + + connect(network, &ZigbeeNetwork::permitJoiningDurationChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RolePermitJoiningDuration}); + }); + + connect(network, &ZigbeeNetwork::permitJoiningRemainingChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RolePermitJoiningRemaining}); + }); + + connect(network, &ZigbeeNetwork::backendChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RoleBackend}); + }); + + connect(network, &ZigbeeNetwork::networkStateChanged, this, [this, network]() { + QModelIndex idx = index(m_networks.indexOf(network), 0); + emit dataChanged(idx, idx, {RoleNetworkState}); + }); + + endInsertRows(); + emit countChanged(); + +} + +void ZigbeeNetworks::removeNetwork(const QUuid &networkUuid) +{ + for (int i = 0; i < m_networks.count(); i++) { + if (m_networks.at(i)->networkUuid() == networkUuid) { + beginRemoveRows(QModelIndex(), i, i); + m_networks.takeAt(i)->deleteLater(); + endRemoveRows(); + emit countChanged(); + return; + } + } +} + +void ZigbeeNetworks::clear() +{ + beginResetModel(); + qDeleteAll(m_networks); + m_networks.clear(); + endResetModel(); + emit countChanged(); +} + +ZigbeeNetwork *ZigbeeNetworks::get(int index) const +{ + if (index < 0 || index >= m_networks.count()) { + return nullptr; + } + return m_networks.at(index); +} + +ZigbeeNetwork *ZigbeeNetworks::getNetwork(const QUuid &networkUuid) const +{ + foreach (ZigbeeNetwork *network, m_networks) { + if (network->networkUuid() == networkUuid) { + return network; + } + } + + return nullptr; +} + +ZigbeeNetwork *ZigbeeNetworks::findBySerialPort(const QString &serialPort) const +{ + foreach (ZigbeeNetwork* network, m_networks) { + if (network->serialPort() == serialPort) { + return network; + } + } + return nullptr; +} diff --git a/libnymea-app/zigbee/zigbeenetworks.h b/libnymea-app/zigbee/zigbeenetworks.h new file mode 100644 index 00000000..bc6f1ba4 --- /dev/null +++ b/libnymea-app/zigbee/zigbeenetworks.h @@ -0,0 +1,86 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 ZIGBEENETWORKS_H +#define ZIGBEENETWORKS_H + +#include +#include + +#include "zigbeenetwork.h" + +class ZigbeeNetworks : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + +public: + enum Roles { + RoleUuid, + RoleSerialPort, + RoleBaudRate, + RoleMacAddress, + RoleFirmwareVersion, + RolePanId, + RoleChannel, + RoleChannelMask, + RolePermitJoiningEnabled, + RolePermitJoiningDuration, + RolePermitJoiningRemaining, + RoleBackend, + RoleNetworkState + }; + Q_ENUM(Roles) + + explicit ZigbeeNetworks(QObject *parent = nullptr); + virtual ~ZigbeeNetworks() override = default; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + + void addNetwork(ZigbeeNetwork *network); + void removeNetwork(const QUuid &networkUuid); + + void clear(); + + Q_INVOKABLE virtual ZigbeeNetwork *get(int index) const; + Q_INVOKABLE ZigbeeNetwork *getNetwork(const QUuid &networkUuid) const; + ZigbeeNetwork *findBySerialPort(const QString &serialPort) const; + +signals: + void countChanged(); + +protected: + QList m_networks; + +}; + +#endif // ZIGBEENETWORKS_H diff --git a/nymea-app/images.qrc b/nymea-app/images.qrc index 4e3c404a..c9423e13 100644 --- a/nymea-app/images.qrc +++ b/nymea-app/images.qrc @@ -241,5 +241,7 @@ ui/images/state-in.svg ui/images/state-out.svg ui/images/like.svg + ui/images/zigbee.svg + ui/images/stock_usb.svg diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc index bea8e76d..ccd269f7 100644 --- a/nymea-app/resources.qrc +++ b/nymea-app/resources.qrc @@ -225,5 +225,9 @@ ui/components/ThingStatusIcons.qml ui/components/InfoPaneBase.qml ui/components/ThingInfoPane.qml + ui/system/ZigbeeSettingsPage.qml + ui/system/ZigbeeAddNetworkPage.qml + ui/system/ZigbeeNetworkPage.qml + ui/system/ZigbeeNetworkInfoPage.qml diff --git a/nymea-app/ui/SettingsPage.qml b/nymea-app/ui/SettingsPage.qml index 726eb19f..36fffc8e 100644 --- a/nymea-app/ui/SettingsPage.qml +++ b/nymea-app/ui/SettingsPage.qml @@ -153,6 +153,23 @@ Page { } } + Pane { + Layout.fillWidth: true + Material.elevation: layout.isGrid ? 1 : 0 + visible: engine.jsonRpcClient.ensureServerVersion("5.3") + + padding: 0 + NymeaListItemDelegate { + width: parent.width + iconName: "../images/zigbee.svg" + text: qsTr("ZigBee") + subText: qsTr("Configure ZigBee networks") + prominentSubText: false + wrapTexts: false + onClicked: pageStack.push(Qt.resolvedUrl("system/ZigbeeSettingsPage.qml")) + } + } + Pane { Layout.fillWidth: true Material.elevation: layout.isGrid ? 1 : 0 diff --git a/nymea-app/ui/images/stock_usb.svg b/nymea-app/ui/images/stock_usb.svg new file mode 100644 index 00000000..9d988a71 --- /dev/null +++ b/nymea-app/ui/images/stock_usb.svg @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/zigbee.svg b/nymea-app/ui/images/zigbee.svg new file mode 100644 index 00000000..5366feb6 --- /dev/null +++ b/nymea-app/ui/images/zigbee.svg @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/system/NetworkSettingsPage.qml b/nymea-app/ui/system/NetworkSettingsPage.qml index 42da6468..f7865de5 100644 --- a/nymea-app/ui/system/NetworkSettingsPage.qml +++ b/nymea-app/ui/system/NetworkSettingsPage.qml @@ -132,6 +132,8 @@ SettingsPageBase { RowLayout { Layout.topMargin: app.margins * 6 + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins visible: !networkManager.available && !networkManager.loading spacing: app.margins ColorIcon { diff --git a/nymea-app/ui/system/ZigbeeAddNetworkPage.qml b/nymea-app/ui/system/ZigbeeAddNetworkPage.qml new file mode 100644 index 00000000..0ead853f --- /dev/null +++ b/nymea-app/ui/system/ZigbeeAddNetworkPage.qml @@ -0,0 +1,217 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 +import Nymea 1.0 + +import "../components" + +SettingsPageBase { + id: root + title: qsTr("Add a new Zigbee network") + busy: d.pendingCommandId != -1 + + property ZigbeeManager zigbeeManager: null + + + QtObject { + id: d + property int pendingCommandId: -1 + + function addNetwork(serialPort, baudRate, backend) { + d.pendingCommandId = root.zigbeeManager.addNetwork(serialPort, baudRate, backend) + } + } + + + Connections { + target: root.zigbeeManager + onAddNetworkReply: { + if (commandId == d.pendingCommandId) { + d.pendingCommandId = -1 + var props = {}; + switch (error) { + case "ZigbeeErrorNoError": + pageStack.pop(); + return; + case "ZigbeeErrorAdapterNotAvailable": + props.text = qsTr("The selected adapter is not available or the selected serial port configration is incorrect."); + break; + case "ZigbeeErrorAdapterAlreadyInUse": + props.text = qsTr("The selected adapter is already in use."); + break; + default: + props.errorCode = error; + } + var comp = Qt.createComponent("../components/ErrorDialog.qml") + var popup = comp.createObject(app, props) + popup.open(); + } + } + } + + SettingsPageSectionHeader { + text: qsTr("Hardware not available") + visible: root.zigbeeManager.adapters.count == 0 + } + + RowLayout { + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + visible: root.zigbeeManager.adapters.count == 0 + spacing: app.margins + ColorIcon { + Layout.preferredHeight: app.iconSize + Layout.preferredWidth: app.iconSize + name: "../images/connections/network-wifi-offline.svg" + } + Label { + Layout.fillWidth: true + wrapMode: Text.WordWrap + text: qsTr("No ZigBee adapters or serial ports are available on this system. Connect a ZigBee adapter via USB or UART serial port.") + } + } + + SettingsPageSectionHeader { + text: qsTr("Available ZigBee adapters") + visible: recognizedAdapters.count > 0 + } + + Label { + Layout.fillWidth: true + Layout.leftMargin: app.margins; Layout.rightMargin: app.margins + text: qsTr("Please select the ZigBee adapter on which the new network will be created.") + font.pixelSize: app.smallFont + wrapMode: Text.WordWrap + visible: recognizedAdapters.count > 0 + } + + + Repeater { + id: recognizedRepeater + model: ZigbeeAdaptersProxy { + id: recognizedAdapters + manager: root.zigbeeManager + hardwareFilter: ZigbeeAdaptersProxy.HardwareFilterRecognized + onlyUnused: true + } + + delegate: NymeaListItemDelegate { + Layout.fillWidth: true + iconName: "../images/zigbee.svg" + text: model.backend + " - " + model.description + " - " + model.serialPort + onClicked: d.addNetwork(model.serialPort, model.baudRate, model.backend) + } + } + + SettingsPageSectionHeader { + text: qsTr("Available serial ports") + visible: serialPorts.count > 0 + } + + Label { + Layout.fillWidth: true; Layout.leftMargin: app.margins; Layout.rightMargin: app.margins + wrapMode: Text.WordWrap + font.pixelSize: app.smallFont + text: qsTr("Please verify that the ZigBee adapter is properly connected to a serial port and select the appropriate port.") + visible: serialPorts.count > 0 + } + + Repeater { + id: unrecognizedRepeater + model: ZigbeeAdaptersProxy { + id: serialPorts + manager: root.zigbeeManager + hardwareFilter: ZigbeeAdaptersProxy.HardwareFilterUnrecognized + onlyUnused: true + } + + delegate: NymeaListItemDelegate { + Layout.fillWidth: true + property ZigbeeAdapter adapter: root.zigbeeManager.adapters.get(index) + iconName: "../images/stock_usb.svg" + text: model.description + " - " + model.serialPort + onClicked: { + var dialog = serialPortOptionsDialogComponent.createObject(app, {serialPort: model.serialPort, baudRate: model.baudRate, backend: model.backend}) + dialog.open() + } + } + } + + + Component { + id: serialPortOptionsDialogComponent + MeaDialog { + id: serialPortOptionsDialog + property string serialPort + property int baudRate + property string backend + + headerIcon: "../images/stock_usb.svg" + title: qsTr("Serial port options") + text: qsTr("Please select the serial port options for using the ZigBee adapter") + standardButtons: Dialog.Ok | Dialog.Cancel + + RowLayout { + Label { + text: qsTr("Adapter") + Layout.fillWidth: true + } + ComboBox { + id: backendComboBox + model: root.zigbeeManager.availableBackends + Component.onCompleted: { + currentIndex = backendComboBox.find(serialPortOptionsDialog.backend) + } + } + } + + RowLayout { + Label { + text: qsTr("Baud rate") + Layout.fillWidth: true + } + ComboBox { + id: baudRateComboBox + model: ["9600", "14400", "19200", "38400", "57600", "115200", "128000", "230400", "256000"] + Component.onCompleted: { + currentIndex = baudRateComboBox.find(serialPortOptionsDialog.baudRate) + } + } + } + + onAccepted: { + d.addNetwork(serialPortOptionsDialog.serialPort, baudRateComboBox.currentText, backendComboBox.currentText) + } + } + } +} diff --git a/nymea-app/ui/system/ZigbeeNetworkInfoPage.qml b/nymea-app/ui/system/ZigbeeNetworkInfoPage.qml new file mode 100644 index 00000000..0b1ecd68 --- /dev/null +++ b/nymea-app/ui/system/ZigbeeNetworkInfoPage.qml @@ -0,0 +1,126 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import QtQuick.Controls.Material 2.1 +import QtQuick.Layouts 1.3 +import "../components" +import Nymea 1.0 + +SettingsPageBase { + id: root + + property ZigbeeManager zigbeeManager: null + + property ZigbeeNetwork network: null + + header: NymeaHeader { + text: qsTr("Network settings") + backButtonVisible: true + onBackPressed: pageStack.pop() + } + + SettingsPageSectionHeader { + text: qsTr("Hardware information") + } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("MAC address:") + subText: root.network.macAddress + progressive: false + prominentSubText: false + } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("Serial port") + subText: root.network.serialPort + progressive: false + prominentSubText: false + } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("Baud rate") + subText: root.network.baudRate + progressive: false + prominentSubText: false + } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("Controller backend") + subText: root.network.backend + progressive: false + prominentSubText: false + } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("Controller firmware version") + subText: root.network.firmwareVersion + progressive: false + prominentSubText: false + } + + SettingsPageSectionHeader { + text: qsTr("Manage network") + } + + ColumnLayout { + + Button { + Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + text: qsTr("Remove network") + onClicked: { + root.zigbeeManager.removeNetwork(root.network.networkUuid) + pageStack.pop() + pageStack.pop() + } + } + + Button { + Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + text: qsTr("Factory reset controller") + onClicked: { + root.zigbeeManager.factoryResetNetwork(root.network.networkUuid) + pageStack.pop() + } + } + } + + +} diff --git a/nymea-app/ui/system/ZigbeeNetworkPage.qml b/nymea-app/ui/system/ZigbeeNetworkPage.qml new file mode 100644 index 00000000..d3ee2247 --- /dev/null +++ b/nymea-app/ui/system/ZigbeeNetworkPage.qml @@ -0,0 +1,138 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import QtQuick.Controls.Material 2.1 +import QtQuick.Layouts 1.3 +import "../components" +import Nymea 1.0 + +SettingsPageBase { + id: root + + property ZigbeeManager zigbeeManager: null + property ZigbeeNetwork network: null + + header: NymeaHeader { + text: qsTr("Network") + " " + root.network.macAddress + backButtonVisible: true + onBackPressed: pageStack.pop() + + HeaderButton { + text: qsTr("Settings") + imageSource: "../images/settings.svg" + onClicked: pageStack.push(Qt.resolvedUrl("ZigbeeNetworkInfoPage.qml"), { network: root.network, zigbeeManager: root.zigbeeManager }) + } + } + + SettingsPageSectionHeader { + text: qsTr("Network information") + } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("Network state") + subText: { + switch (root.network.networkState) { + case ZigbeeNetwork.ZigbeeNetworkStateOnline: + return qsTr("The network is online") + case ZigbeeNetwork.ZigbeeNetworkStateOffline: + return qsTr("The network is offline") + case ZigbeeNetwork.ZigbeeNetworkStateStarting: + return qsTr("The network is starting...") + case ZigbeeNetwork.ZigbeeNetworkStateUpdating: + return qsTr("The controller is currently installing an update") + case ZigbeeNetwork.ZigbeeNetworkStateError: + return qsTr("The network is in an error state.") + } + } + + progressive: false + } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("Channel") + subText: root.network.channel + progressive: false + } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("Network PAN ID") + subText: root.network.panId + progressive: false + } + + SettingsPageSectionHeader { + text: qsTr("Network control") + } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: root.network.permitJoiningEnabled ? qsTr("The network is open") : qsTr("The network is closed") + subText: root.network.permitJoiningEnabled ? qsTr("Devices can join this network") : qsTr("Devices are not allowed to join this network") + progressive: false + prominentSubText: false + } + + ColumnLayout { + + ProgressBar { + Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + visible: root.network.permitJoiningEnabled + from: root.network.permitJoiningDuration + to: 0 + value: root.network.permitJoiningRemaining + } + + Button { + Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + enabled: network.networkState === ZigbeeNetwork.ZigbeeNetworkStateOnline + text: root.network.permitJoiningEnabled ? qsTr("Extend network open duration") : qsTr("Open network for new ZigBee devices") + onClicked: root.zigbeeManager.setPermitJoin(root.network.networkUuid) + } + + Button { + Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + visible: network.networkState === ZigbeeNetwork.ZigbeeNetworkStateOnline && root.network.permitJoiningEnabled + text: qsTr("Close network") + onClicked: root.zigbeeManager.setPermitJoin(root.network.networkUuid, 0) + } + } + +} diff --git a/nymea-app/ui/system/ZigbeeSettingsPage.qml b/nymea-app/ui/system/ZigbeeSettingsPage.qml new file mode 100644 index 00000000..a100936c --- /dev/null +++ b/nymea-app/ui/system/ZigbeeSettingsPage.qml @@ -0,0 +1,104 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import QtQuick.Controls.Material 2.1 +import QtQuick.Layouts 1.3 +import "../components" +import Nymea 1.0 + +SettingsPageBase { + id: root + header: NymeaHeader { + text: qsTr("ZigBee") + backButtonVisible: true + onBackPressed: pageStack.pop() + + HeaderButton { + imageSource: "../images/add.svg" + text: qsTr("Add ZigBee network") + onClicked: pageStack.push(Qt.resolvedUrl("ZigbeeAddNetworkPage.qml"), {zigbeeManager: zigbeeManager}) + } + } + + ZigbeeManager { + id: zigbeeManager + engine: _engine + } + + // Disabled for now, the Resources API won't make it in time +// SettingsPageSectionHeader { +// text: qsTr("General") +// } + +// NymeaListItemDelegate { +// Layout.fillWidth: true +// text: qsTr("Zigbee enabled") +// subText: qsTr("Enable or disable Zigbee altogether") +// prominentSubText: false +// progressive: false +// additionalItem: Switch { +// anchors.centerIn: parent +// } +// } + + SettingsPageSectionHeader { + text: qsTr("ZigBee networks") + } + + Label { + Layout.fillWidth: true + Layout.leftMargin: app.margins; Layout.rightMargin: app.margins + wrapMode: Text.WordWrap + text: qsTr("There are no ZigBee networks set up yet. In order to use ZigBee, create a ZigBee network.") + visible: zigbeeManager.networks.count == 0 + } + + Repeater { + model: zigbeeManager.networks + delegate: NymeaListItemDelegate { + Layout.fillWidth: true + property var network: zigbeeManager.networks.get(index) + iconName: "../images/zigbee.svg" + text: model.backend + " - " + model.macAddress + subText: model.serialPort + " - " + model.firmwareVersion + onClicked: pageStack.push(Qt.resolvedUrl("ZigbeeNetworkPage.qml"), { zigbeeManager: zigbeeManager, network: network }) + } + } + + Button { + Layout.fillWidth: true + Layout.margins: app.margins + text: qsTr("Add a ZigBee network") + onClicked: pageStack.push(Qt.resolvedUrl("ZigbeeAddNetworkPage.qml"), {zigbeeManager: zigbeeManager}) + } +} +