diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index ee2f1480..c64bc987 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -31,6 +31,7 @@ #include "zigbeehandler.h" #include "zigbee/zigbeemanager.h" #include "zigbee/zigbeeadapters.h" +#include "loggingcategories.h" #include @@ -40,6 +41,9 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : JsonHandler(parent), m_zigbeeManager(zigbeeManager) { + qRegisterMetaType(); + qRegisterMetaType(); + registerEnum(); registerEnum(); registerEnum(); @@ -48,7 +52,16 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // Network object describing a network instance QVariantMap zigbeeNetworkDescription; - zigbeeNetworkDescription.insert("uuid", enumValueName(Uuid)); + zigbeeNetworkDescription.insert("networkUuid", enumValueName(Uuid)); + zigbeeNetworkDescription.insert("serialPort", enumValueName(String)); + zigbeeNetworkDescription.insert("baudRate", enumValueName(Uint)); + zigbeeNetworkDescription.insert("macAddress", enumValueName(String)); + zigbeeNetworkDescription.insert("panId", enumValueName(Uint)); + zigbeeNetworkDescription.insert("channel", enumValueName(Uint)); + zigbeeNetworkDescription.insert("channelMask", enumValueName(Uint)); + zigbeeNetworkDescription.insert("permitJoin", enumValueName(Bool)); + zigbeeNetworkDescription.insert("backendType", enumRef()); + zigbeeNetworkDescription.insert("networkState", enumRef()); registerObject("ZigbeeNetwork", zigbeeNetworkDescription); QVariantMap params, returns; @@ -56,7 +69,9 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // GetAdapters params.clear(); returns.clear(); - description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network on the desired serial interface. If an adapter hardware has been recognized as a supported hardware, the \'hardwareRecognized\' property will be true and the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; + description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network on the desired serial interface." + "If an adapter hardware has been recognized as a supported hardware, the \'hardwareRecognized\' property will be true and " + "the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; returns.insert("adapters", objectRef()); registerMethod("GetAdapters", description, params, returns); @@ -72,21 +87,46 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : params.insert("adapters", objectRef()); registerNotification("AdapterRemoved", description, params); + // GetNetworks params.clear(); returns.clear(); - description = "Get the status of the current network."; - returns.insert("available", enumValueName(Bool)); - returns.insert("enabled", enumValueName(Bool)); - returns.insert("configured", enumValueName(Bool)); - returns.insert("serialPort", enumValueName(String)); - returns.insert("baudRate", enumValueName(Uint)); - returns.insert("backend", enumRef()); - returns.insert("firmwareVersion", enumValueName(String)); - returns.insert("networkIeeeeAddress", enumValueName(String)); - returns.insert("networkPanId", enumValueName(Uint)); - returns.insert("channel", enumValueName(Uint)); - returns.insert("permitJoin", enumValueName(Bool)); - returns.insert("networkState", enumRef()); - registerMethod("GetNetworkStatus", description, params, returns); + description = "Returns the list of current configured zigbee networks."; + returns.insert("zigbeeNetworks", QVariantList() << objectRef("ZigbeeNetwork")); + registerMethod("GetNetworks", description, params, returns); + + // AddNetwork + params.clear(); returns.clear(); + description = "Create a new zigbee network for the given zigbee adapter. The channel mask is optional and defaults to all channels. " + "The quietest channel will be picked. The channel mask type is a TODO and will probably be a flag."; + params.insert("adapter", objectRef()); + params.insert("o:channelMask", enumValueName(Uint)); + returns.insert("zigbeeError", enumRef()); + registerMethod("AddNetwork", description, params, returns); + + // RemoveNetwork + params.clear(); returns.clear(); + description = "Remove the zigbee network with the given network uuid"; + params.insert("networkUuid", enumValueName(Uuid)); + returns.insert("zigbeeError", enumRef()); + registerMethod("RemoveNetwork", description, params, returns); + + // NetworkAdded notification + params.clear(); + description = "Emitted whenever a new ZigBee network has been added."; + params.insert("network", objectRef("ZigbeeNetwork")); + registerNotification("NetworkAdded", description, params); + + // NetworkRemoved notification + params.clear(); + description = "Emitted whenever a new ZigBee network has been removed."; + params.insert("networkUuid", enumValueName(Uuid)); + registerNotification("NetworkRemoved", description, params); + + // NetworkChanged notification + params.clear(); + description = "Emitted whenever a new ZigBee network has changed."; + params.insert("network", objectRef("ZigbeeNetwork")); + registerNotification("NetworkChanged", description, params); + connect(m_zigbeeManager, &ZigbeeManager::availableAdapterAdded, this, [this](const ZigbeeAdapter &adapter){ QVariantMap params; @@ -100,32 +140,23 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : emit AdapterRemoved(params); }); - /* 1. GetNetworks - * 2. Setup network if the is no network configured - * - GetAdapters - * - AddNetwork (adapter, channelmask) - * - - */ + connect(m_zigbeeManager, &ZigbeeManager::zigbeeNetworkAdded, this, [this](ZigbeeNetwork *network){ + QVariantMap params; + params.insert("zigbeeNetwork", packNetwork(network)); + emit NetworkAdded(params); + }); - // GetNetworkStatus - // NetworkStatusChanged - // SetupNetwork(network, uart, baudrate, backendtype) - // PermitJoin(time, o:nwk address) - // FactoryResetNetwork - - // GetNodes [Node(mac, nwkAddress, name, manufacturer, type, descriptors, associacted device, state, reachable)] - // NodeAdded - // NodeChanged (state, node base information, associated deviceId) - // RemoveNode - // NodeRemoved - - // GetGroups - // GroupChanged - // AddGroup - // GroupAdded - // RemoveGroup - // GroupRemoved + connect(m_zigbeeManager, &ZigbeeManager::zigbeeNetworkChanged, this, [this](ZigbeeNetwork *network){ + QVariantMap params; + params.insert("zigbeeNetwork", packNetwork(network)); + emit NetworkChanged(params); + }); + connect(m_zigbeeManager, &ZigbeeManager::zigbeeNetworkRemoved, this, [this](const QUuid &networkUuid){ + QVariantMap params; + params.insert("networkUuid", networkUuid.toString()); + emit NetworkRemoved(params); + }); } QString ZigbeeHandler::name() const @@ -133,26 +164,6 @@ QString ZigbeeHandler::name() const return "Zigbee"; } -JsonReply *ZigbeeHandler::GetNetworkStatus(const QVariantMap ¶ms) -{ - Q_UNUSED(params) - - QVariantMap ret; -// if (m_zigbeeManager->zigbeeNetwork()) { -// ret.insert("available", m_zigbeeManager->available()); -// ret.insert("enabled", m_zigbeeManager->enabled()); -// ret.insert("configured", true); -// ret.insert("networkState", m_zigbeeManager->zigbeeNetwork()->state()); -// } else { -// ret.insert("available", m_zigbeeManager->available()); -// ret.insert("enabled", m_zigbeeManager->enabled()); -// ret.insert("configured", false); -// ret.insert("state", ZigbeeNetwork::StateUninitialized); -// } - - return createReply(ret); -} - JsonReply *ZigbeeHandler::GetAdapters(const QVariantMap ¶ms) { Q_UNUSED(params) @@ -166,4 +177,77 @@ JsonReply *ZigbeeHandler::GetAdapters(const QVariantMap ¶ms) return createReply(returnMap); } +JsonReply *ZigbeeHandler::AddNetwork(const QVariantMap ¶ms) +{ + ZigbeeAdapter adapter = unpack(params.value("adapter")); + ZigbeeManager::ZigbeeError error = m_zigbeeManager->createZigbeeNetwork(adapter); + QVariantMap returnMap; + returnMap.insert("zigbeeError", enumValueName(error)); + return createReply(returnMap); +} + +JsonReply *ZigbeeHandler::RemoveNetwork(const QVariantMap ¶ms) +{ + QUuid networkUuid = params.value("networkUuid").toUuid(); + ZigbeeManager::ZigbeeError error = m_zigbeeManager->removeZigbeeNetwork(networkUuid); + QVariantMap returnMap; + returnMap.insert("zigbeeError", enumValueName(error)); + return createReply(returnMap); +} + +JsonReply *ZigbeeHandler::GetNetworks(const QVariantMap ¶ms) +{ + Q_UNUSED(params) + + QVariantMap returnMap; + QVariantList networkList; + foreach (ZigbeeNetwork *network, m_zigbeeManager->zigbeeNetworks().values()) { + networkList.append(packNetwork(network)); + } + returnMap.insert("zigbeeNetworks", networkList); + return createReply(returnMap); +} + +QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network) +{ + QVariantMap networkMap; + networkMap.insert("networkUuid", network->networkUuid()); + networkMap.insert("serialPort", network->serialPortName()); + networkMap.insert("baudRate", network->serialBaudrate()); + networkMap.insert("macAddress", network->macAddress().toString()); + networkMap.insert("panId", network->panId()); + networkMap.insert("channel", network->channel()); + networkMap.insert("channelMask", network->channelMask().toUInt32()); + networkMap.insert("permitJoin", network->permitJoining()); + switch (network->backendType()) { + case Zigbee::ZigbeeBackendTypeDeconz: + networkMap.insert("backendType", enumValueName(ZigbeeAdapter::ZigbeeBackendTypeDeconz)); + break; + case Zigbee::ZigbeeBackendTypeNxp: + networkMap.insert("backendType", enumValueName(ZigbeeAdapter::ZigbeeBackendTypeNxp)); + break; + } + + switch (network->state()) { + case ZigbeeNetwork::StateOffline: + case ZigbeeNetwork::StateStopping: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateOffline)); + break; + case ZigbeeNetwork::StateStarting: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateStarting)); + break; + case ZigbeeNetwork::StateRunning: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateOnline)); + break; + case ZigbeeNetwork::StateUpdating: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateUpdating)); + break; + case ZigbeeNetwork::StateUninitialized: + networkMap.insert("networkState", enumValueName(ZigbeeManager::ZigbeeNetworkStateError)); + break; + } + + return networkMap; +} + } diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h index 3b99035a..b7656347 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.h +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -49,8 +49,12 @@ public: QString name() const override; - Q_INVOKABLE JsonReply *GetNetworkStatus(const QVariantMap ¶ms); Q_INVOKABLE JsonReply *GetAdapters(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetNetworks(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *AddNetwork(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *RemoveNetwork(const QVariantMap ¶ms); + + QVariantMap packNetwork(ZigbeeNetwork *network); private: ZigbeeManager *m_zigbeeManager = nullptr; @@ -58,6 +62,9 @@ private: signals: void AdapterAdded(const QVariantMap ¶ms); void AdapterRemoved(const QVariantMap ¶ms); + void NetworkAdded(const QVariantMap ¶ms); + void NetworkRemoved(const QVariantMap ¶ms); + void NetworkChanged(const QVariantMap ¶ms); }; diff --git a/libnymea-core/zigbee/zigbeeadapter.cpp b/libnymea-core/zigbee/zigbeeadapter.cpp index ce1af680..27205acd 100644 --- a/libnymea-core/zigbee/zigbeeadapter.cpp +++ b/libnymea-core/zigbee/zigbeeadapter.cpp @@ -113,7 +113,7 @@ QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter) debug.nospace() << "ZigbeeAdapter(" << adapter.name() << " - " << adapter.description(); debug.nospace() << ", " << adapter.systemLocation(); if (adapter.hardwareRecognized()) { - debug.nospace() << "Hardware recognized: " << adapter.backendType(); + debug.nospace() << " Hardware recognized: " << adapter.backendType(); debug.nospace() << ", " << adapter.baudRate(); } diff --git a/libnymea-core/zigbee/zigbeeadapter.h b/libnymea-core/zigbee/zigbeeadapter.h index 08f88c18..fcc3e6ac 100644 --- a/libnymea-core/zigbee/zigbeeadapter.h +++ b/libnymea-core/zigbee/zigbeeadapter.h @@ -41,12 +41,12 @@ namespace nymeaserver { class ZigbeeAdapter { Q_GADGET - Q_PROPERTY(QString name READ name) - Q_PROPERTY(QString description READ description) - Q_PROPERTY(QString systemLocation READ systemLocation) - Q_PROPERTY(bool hardwareRecognized READ hardwareRecognized) - Q_PROPERTY(ZigbeeAdapter::ZigbeeBackendType backendType READ backendType) - Q_PROPERTY(qint32 baudRate READ baudRate) + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString description READ description WRITE setDescription) + Q_PROPERTY(QString systemLocation READ systemLocation WRITE setSystemLocation) + Q_PROPERTY(bool hardwareRecognized READ hardwareRecognized WRITE setHardwareRecognized) + Q_PROPERTY(nymeaserver::ZigbeeAdapter::ZigbeeBackendType backendType READ backendType WRITE setBackendType) + Q_PROPERTY(qint32 baudRate READ baudRate WRITE setBaudRate) public: enum ZigbeeBackendType { @@ -91,6 +91,7 @@ QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter); } Q_DECLARE_METATYPE(nymeaserver::ZigbeeAdapter) +Q_DECLARE_METATYPE(nymeaserver::ZigbeeAdapter::ZigbeeBackendType) #endif // ZIGBEEADAPTER_H diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index c3c29081..3dc5ac31 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -95,6 +95,11 @@ ZigbeeAdapters ZigbeeManager::availableAdapters() const return m_adapters; } +QHash ZigbeeManager::zigbeeNetworks() const +{ + return m_zigbeeNetworks; +} + ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask) { qCDebug(dcZigbee()) << "Start creating network for" << adapter << channelMask; @@ -124,6 +129,32 @@ ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapte return ZigbeeErrorNoError; } +ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &networkUuid) +{ + if (!m_zigbeeNetworks.keys().contains(networkUuid)) { + qCDebug(dcZigbee()) << "Could not remove network with uuid" << networkUuid.toString() << "because there is no network with this uuid."; + return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; + } + + qCDebug(dcZigbee()) << "Removing network" << networkUuid.toString(); + ZigbeeNetwork *network = m_zigbeeNetworks.take(networkUuid); + // Note: destroy will remove all nodes from the network and wipe/delete the database + network->destroyNetwork(); + emit zigbeeNetworkRemoved(network->networkUuid()); + // Make sure to delete later, so all node removed signals can be processed + network->deleteLater(); + + NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); + settings.beginGroup("ZigbeeNetworks"); + settings.beginGroup(network->networkUuid().toString()); + settings.remove(""); + settings.endGroup(); + settings.endGroup(); + + qCDebug(dcZigbee()) << "Network removed successfully" << networkUuid.toString(); + return ZigbeeManager::ZigbeeErrorNoError; +} + void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) { NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); @@ -144,7 +175,7 @@ void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) } settings.setValue("panId", network->panId()); settings.setValue("channel", network->channel()); - + settings.setValue("macAddress", network->macAddress().toString()); settings.setValue("channelMask", network->channelMask().toUInt32()); settings.setValue("networkKey", network->securityConfiguration().networkKey().toString()); settings.setValue("trustCenterLinkKey", network->securityConfiguration().globalTrustCenterLinkKey().toString()); @@ -168,7 +199,7 @@ void ZigbeeManager::loadZigbeeNetworks() quint16 panId = static_cast(settings.value("panId", 0).toUInt()); quint8 channel = settings.value("channel", 0).toUInt(); ZigbeeChannelMask channelMask = ZigbeeChannelMask(static_cast(settings.value("channelMask").toUInt())); - + ZigbeeAddress macAddress = ZigbeeAddress(settings.value("macAddress").toString()); ZigbeeSecurityConfiguration securityConfiguration; ZigbeeNetworkKey netKey(settings.value("networkKey", QString()).toString()); if (netKey.isValid()) { @@ -183,6 +214,7 @@ void ZigbeeManager::loadZigbeeNetworks() ZigbeeNetwork *network = buildNetworkObject(networkUuid, backendType); network->setSerialPortName(serialPortName); network->setSerialBaudrate(serialBaudRate); + network->setMacAddress(macAddress); network->setPanId(panId); network->setChannel(channel); network->setChannelMask(channelMask); @@ -245,6 +277,12 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) emit zigbeeNetworkChanged(network); }); + connect(network, &ZigbeeNetwork::macAddressChanged, this, [this, network](const ZigbeeAddress &macAddress){ + qCDebug(dcZigbee()) << "Network MAC address changed" << network->networkUuid().toString() << macAddress.toString(); + saveNetwork(network); + emit zigbeeNetworkChanged(network); + }); + connect(network, &ZigbeeNetwork::securityConfigurationChanged, this, [this, network](const ZigbeeSecurityConfiguration &securityConfiguration){ qCDebug(dcZigbee()) << "Network security configuration changed" << network->networkUuid().toString() << securityConfiguration.networkKey().toString(); saveNetwork(network); @@ -256,6 +294,19 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) emit zigbeeNetworkChanged(network); }); + connect(network, &ZigbeeNetwork::permitJoiningChanged, this, [this, network](bool permitJoiningChanged){ + qCDebug(dcZigbee()) << "Network permit joining changed" << network->networkUuid().toString() << permitJoiningChanged; + emit zigbeeNetworkChanged(network); + }); + + connect(network, &ZigbeeNetwork::nodeAdded, this, [network](ZigbeeNode *node){ + qCDebug(dcZigbee()) << "Network node added to network" << network->networkUuid().toString() << node; + }); + + connect(network, &ZigbeeNetwork::nodeRemoved, this, [network](ZigbeeNode *node){ + qCDebug(dcZigbee()) << "Network node removed from network" << network->networkUuid().toString() << node; + }); + m_zigbeeNetworks.insert(network->networkUuid(), network); emit zigbeeNetworkAdded(network); } diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index b0c2c14a..d75e9a9a 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -46,6 +46,7 @@ class ZigbeeManager : public QObject public: enum ZigbeeNetworkState { ZigbeeNetworkStateOffline, + ZigbeeNetworkStateStarting, ZigbeeNetworkStateUpdating, ZigbeeNetworkStateOnline, ZigbeeNetworkStateError @@ -55,7 +56,8 @@ public: enum ZigbeeError { ZigbeeErrorNoError, ZigbeeErrorAdapterNotAvailable, - ZigbeeErrorAdapterAlreadyInUse + ZigbeeErrorAdapterAlreadyInUse, + ZigbeeErrorNetworkUuidNotFound }; Q_ENUM(ZigbeeError) @@ -65,13 +67,14 @@ public: bool enabled() const; ZigbeeAdapters availableAdapters() const; + QHash zigbeeNetworks() const; - ZigbeeError createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask = ZigbeeChannelMask()); + ZigbeeError createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); + ZigbeeError removeZigbeeNetwork(const QUuid &networkUuid); private: ZigbeeAdapters m_adapters; ZigbeeUartAdapterMonitor *m_adapterMonitor = nullptr; - QHash m_zigbeeNetworks; void saveNetwork(ZigbeeNetwork *network); @@ -87,7 +90,7 @@ signals: void availableAdapterRemoved(const ZigbeeAdapter &adapter); void zigbeeNetworkAdded(ZigbeeNetwork *zigbeeNetwork); - void zigbeeNetworkRemoved(ZigbeeNetwork *zigbeeNetwork); + void zigbeeNetworkRemoved(const QUuid networkUuid); void zigbeeNetworkChanged(ZigbeeNetwork *zigbeeNetwork); };