From 6edf6977a424f5c3ee8cc920b7d1766a2087071f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sun, 1 Nov 2020 22:16:57 +0100 Subject: [PATCH] Add factory reset network and start implementing permit join mechanism --- libnymea-core/jsonrpc/zigbeehandler.cpp | 66 ++++++++++++++++++++++--- libnymea-core/jsonrpc/zigbeehandler.h | 2 + libnymea-core/zigbee/zigbeemanager.cpp | 59 ++++++++++++++++++---- libnymea-core/zigbee/zigbeemanager.h | 7 ++- 4 files changed, 115 insertions(+), 19 deletions(-) diff --git a/libnymea-core/jsonrpc/zigbeehandler.cpp b/libnymea-core/jsonrpc/zigbeehandler.cpp index c64bc987..4f84f53c 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.cpp +++ b/libnymea-core/jsonrpc/zigbeehandler.cpp @@ -56,6 +56,7 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : zigbeeNetworkDescription.insert("serialPort", enumValueName(String)); zigbeeNetworkDescription.insert("baudRate", enumValueName(Uint)); zigbeeNetworkDescription.insert("macAddress", enumValueName(String)); + zigbeeNetworkDescription.insert("firmwareVersion", enumValueName(String)); zigbeeNetworkDescription.insert("panId", enumValueName(Uint)); zigbeeNetworkDescription.insert("channel", enumValueName(Uint)); zigbeeNetworkDescription.insert("channelMask", enumValueName(Uint)); @@ -69,9 +70,11 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // GetAdapters params.clear(); returns.clear(); - description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network on the desired serial interface." - "If an adapter hardware has been recognized as a supported hardware, the \'hardwareRecognized\' property will be true and " - "the configurations can be used as they where given, otherwise the user might set the backend type and baud rate manually."; + description = "Get the list of available ZigBee adapter candidates in order to set up the zigbee network " + "on the desired serial interface. If an adapter hardware has been recognized as a supported " + "hardware, the \'hardwareRecognized\' property will be true and the serial port and backend " + "configurations can be used as they where given, otherwise the user might set the backend " + "type and baud rate manually."; returns.insert("adapters", objectRef()); registerMethod("GetAdapters", description, params, returns); @@ -84,19 +87,22 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : // AdapterRemoved notification params.clear(); description = "Emitted whenever a ZigBee adapter has been removed from the system (i.e. unplugged)."; - params.insert("adapters", objectRef()); + params.insert("adapter", objectRef()); registerNotification("AdapterRemoved", description, params); // GetNetworks params.clear(); returns.clear(); - description = "Returns the list of current configured zigbee networks."; + description = "Returns the list of zigbee networks configured in the system."; returns.insert("zigbeeNetworks", QVariantList() << objectRef("ZigbeeNetwork")); registerMethod("GetNetworks", description, params, returns); // AddNetwork params.clear(); returns.clear(); - description = "Create a new zigbee network for the given zigbee adapter. The channel mask is optional and defaults to all channels. " - "The quietest channel will be picked. The channel mask type is a TODO and will probably be a flag."; + description = "Create a new zigbee network for the given zigbee adapter. " + "The channel mask is optional and defaults to all channels [11, 26]. " + "The quietest channel will be picked after a channel scan. " + "The channel mask is a uint32 flag and the the bit number represents the channel which should " + "enabled for scanning. All channels would be the value 0x07fff800."; params.insert("adapter", objectRef()); params.insert("o:channelMask", enumValueName(Uint)); returns.insert("zigbeeError", enumRef()); @@ -127,6 +133,28 @@ ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : params.insert("network", objectRef("ZigbeeNetwork")); registerNotification("NetworkChanged", description, params); + // FactoryResetNetwork + params.clear(); returns.clear(); + description = "Factory reset the network with the given networkUuid. The network does not have " + "to be Online for this procedure, and all associated nodes and things will be removed permanently. " + "Make sure the user realy wants to do this because this can not be undone."; + params.insert("networkUuid", enumValueName(Uuid)); + returns.insert("zigbeeError", enumRef()); + registerMethod("FactoryResetNetwork", description, params, returns); + + // SetPermitJoin + params.clear(); returns.clear(); + description = "Allow or deny nodes to join the network with the given networkUuid for a specific duration in seconds. " + "If the duration is set to 0 seconds, joining will be disabled immediatly for the entire network. " + "The shortAddress is optional and defaults to the broadcast address (0xfffc) for all routers in the network. " + "If the short address matches the address of a router node in the network, only that router will " + "be able to allow new nodes to join the network. A new node will join to the router with the best LQI."; + params.insert("networkUuid", enumValueName(Uuid)); + params.insert("timeout", enumValueName(Uint)); + params.insert("o:shortAddress", enumValueName(Uint)); + returns.insert("zigbeeError", enumRef()); + registerMethod("SetPermitJoin", description, params, returns); + connect(m_zigbeeManager, &ZigbeeManager::availableAdapterAdded, this, [this](const ZigbeeAdapter &adapter){ QVariantMap params; @@ -195,6 +223,29 @@ JsonReply *ZigbeeHandler::RemoveNetwork(const QVariantMap ¶ms) return createReply(returnMap); } +JsonReply *ZigbeeHandler::FactoryResetNetwork(const QVariantMap ¶ms) +{ + QUuid networkUuid = params.value("networkUuid").toUuid(); + ZigbeeManager::ZigbeeError error = m_zigbeeManager->factoryResetNetwork(networkUuid); + QVariantMap returnMap; + returnMap.insert("zigbeeError", enumValueName(error)); + return createReply(returnMap); +} + +JsonReply *ZigbeeHandler::SetPermitJoin(const QVariantMap ¶ms) +{ + QUuid networkUuid = params.value("networkUuid").toUuid(); + uint duration = params.value("duration").toUInt(); + quint16 shortAddress = static_cast(Zigbee::BroadcastAddressAllRouters); + if (params.contains("shortAddress")) { + shortAddress = static_cast(params.value("shortAddress").toUInt()); + } + ZigbeeManager::ZigbeeError error = m_zigbeeManager->setZigbeeNetworkPermitJoin(networkUuid, shortAddress, duration); + QVariantMap returnMap; + returnMap.insert("zigbeeError", enumValueName(error)); + return createReply(returnMap); +} + JsonReply *ZigbeeHandler::GetNetworks(const QVariantMap ¶ms) { Q_UNUSED(params) @@ -215,6 +266,7 @@ QVariantMap ZigbeeHandler::packNetwork(ZigbeeNetwork *network) networkMap.insert("serialPort", network->serialPortName()); networkMap.insert("baudRate", network->serialBaudrate()); networkMap.insert("macAddress", network->macAddress().toString()); + networkMap.insert("firmwareVersion", network->firmwareVersion()); networkMap.insert("panId", network->panId()); networkMap.insert("channel", network->channel()); networkMap.insert("channelMask", network->channelMask().toUInt32()); diff --git a/libnymea-core/jsonrpc/zigbeehandler.h b/libnymea-core/jsonrpc/zigbeehandler.h index b7656347..a5c6b614 100644 --- a/libnymea-core/jsonrpc/zigbeehandler.h +++ b/libnymea-core/jsonrpc/zigbeehandler.h @@ -53,6 +53,8 @@ public: Q_INVOKABLE JsonReply *GetNetworks(const QVariantMap ¶ms); Q_INVOKABLE JsonReply *AddNetwork(const QVariantMap ¶ms); Q_INVOKABLE JsonReply *RemoveNetwork(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *FactoryResetNetwork(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *SetPermitJoin(const QVariantMap ¶ms); QVariantMap packNetwork(ZigbeeNetwork *network); diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index 3dc5ac31..77424340 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -32,6 +32,8 @@ #include "nymeasettings.h" #include "loggingcategories.h" +#include + NYMEA_LOGGING_CATEGORY(dcZigbee, "Zigbee") // Register debug category from the libnymea-zigbee @@ -52,13 +54,13 @@ ZigbeeManager::ZigbeeManager(QObject *parent) : qCDebug(dcZigbee()) << "Loading initial adapter list"; foreach(const ZigbeeUartAdapter &uartAdapter, m_adapterMonitor->availableAdapters()) { - ZigbeeAdapter adapter = createAdapterFromUartAdapter(uartAdapter); + ZigbeeAdapter adapter = convertUartAdapterToAdapter(uartAdapter); qCDebug(dcZigbee()) << "Adapter added" << adapter; m_adapters.append(adapter); } connect(m_adapterMonitor, &ZigbeeUartAdapterMonitor::adapterAdded, this, [this](const ZigbeeUartAdapter &uartAdapter){ - ZigbeeAdapter adapter = createAdapterFromUartAdapter(uartAdapter); + ZigbeeAdapter adapter = convertUartAdapterToAdapter(uartAdapter); qCDebug(dcZigbee()) << "Adapter added" << adapter; m_adapters.append(adapter); emit availableAdapterAdded(adapter); @@ -107,7 +109,7 @@ ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapte // Make sure we don't have aleardy a network for this adapter foreach (ZigbeeNetwork *existingNetwork, m_zigbeeNetworks.values()) { if (existingNetwork->serialPortName() == adapter.systemLocation()) { - qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "which is already in use for network" << existingNetwork->networkUuid().toString(); + qCWarning(dcZigbee()) << "Failed to create a network for" << adapter << "because this adapter is already in use for network" << existingNetwork->networkUuid().toString(); return ZigbeeManager::ZigbeeErrorAdapterAlreadyInUse; } } @@ -132,7 +134,7 @@ ZigbeeManager::ZigbeeError ZigbeeManager::createZigbeeNetwork(const ZigbeeAdapte ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &networkUuid) { if (!m_zigbeeNetworks.keys().contains(networkUuid)) { - qCDebug(dcZigbee()) << "Could not remove network with uuid" << networkUuid.toString() << "because there is no network with this uuid."; + qCWarning(dcZigbee()) << "Could not remove network with uuid" << networkUuid.toString() << "because there is no network with this uuid."; return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; } @@ -144,6 +146,7 @@ ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &netwo // Make sure to delete later, so all node removed signals can be processed network->deleteLater(); + // Delete network settings NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); settings.beginGroup("ZigbeeNetworks"); settings.beginGroup(network->networkUuid().toString()); @@ -155,6 +158,37 @@ ZigbeeManager::ZigbeeError ZigbeeManager::removeZigbeeNetwork(const QUuid &netwo return ZigbeeManager::ZigbeeErrorNoError; } +ZigbeeManager::ZigbeeError ZigbeeManager::setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress, int duration) +{ + if (!m_zigbeeNetworks.keys().contains(networkUuid)) { + qCWarning(dcZigbee()) << "Could not set permit join network" << networkUuid.toString() << "because there is no network with this uuid."; + return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; + } + + ZigbeeNetwork *network = m_zigbeeNetworks.value(networkUuid); + if (network->state() != ZigbeeNetwork::StateRunning) { + qCWarning(dcZigbee()) << "Could not set permit join network" << networkUuid.toString() << "because the network is not running."; + return ZigbeeManager::ZigbeeErrorNetworkOffline; + } + + // TODO: set permit join + + qCDebug(dcZigbee()) << "Set permit join for network" << networkUuid.toString() << ZigbeeUtils::convertUint16ToHexString(shortAddress) << "to" << duration << "[s] successfully."; + return ZigbeeManager::ZigbeeErrorNoError; +} + +ZigbeeManager::ZigbeeError ZigbeeManager::factoryResetNetwork(const QUuid &networkUuid) +{ + if (!m_zigbeeNetworks.keys().contains(networkUuid)) { + qCWarning(dcZigbee()) << "Could not factory reset network with uuid" << networkUuid.toString() << "because there is no network with this uuid."; + return ZigbeeManager::ZigbeeErrorNetworkUuidNotFound; + } + + ZigbeeNetwork *network = m_zigbeeNetworks.value(networkUuid); + network->factoryResetNetwork(); + return ZigbeeManager::ZigbeeErrorNoError; +} + void ZigbeeManager::saveNetwork(ZigbeeNetwork *network) { NymeaSettings settings(NymeaSettings::SettingsRoleZigbee); @@ -260,7 +294,7 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) }); connect(network, &ZigbeeNetwork::errorOccured, this, [network](ZigbeeNetwork::Error error){ - qCDebug(dcZigbee()) << "Network error occured for network" << network->networkUuid().toString() << error; + qCWarning(dcZigbee()) << "Network error occured for network" << network->networkUuid().toString() << error; // TODO: handle error }); @@ -307,19 +341,24 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) qCDebug(dcZigbee()) << "Network node removed from network" << network->networkUuid().toString() << node; }); + connect(network, &ZigbeeNetwork::firmwareVersionChanged, this, [this, network](const QString &firmwareVersion){ + qCDebug(dcZigbee()) << "Network adapter firmware version changed" << network->networkUuid().toString() << firmwareVersion; + emit zigbeeNetworkChanged(network); + }); + m_zigbeeNetworks.insert(network->networkUuid(), network); emit zigbeeNetworkAdded(network); } -ZigbeeAdapter ZigbeeManager::createAdapterFromUartAdapter(const ZigbeeUartAdapter &uartAdapter) +ZigbeeAdapter ZigbeeManager::convertUartAdapterToAdapter(const ZigbeeUartAdapter &uartAdapter) { ZigbeeAdapter adapter; adapter.setName(uartAdapter.name()); adapter.setSystemLocation(uartAdapter.systemLocation()); adapter.setDescription(uartAdapter.description()); - adapter.setHardwareRecognized(uartAdapter.backendSuggestionAvailable()); - adapter.setBaudRate(uartAdapter.suggestedBaudRate()); - switch (uartAdapter.suggestedZigbeeBackendType()) { + adapter.setHardwareRecognized(uartAdapter.hardwareRecognized()); + adapter.setBaudRate(uartAdapter.baudRate()); + switch (uartAdapter.zigbeeBackend()) { case Zigbee::ZigbeeBackendTypeDeconz: adapter.setBackendType(ZigbeeAdapter::ZigbeeBackendTypeDeconz); break; @@ -327,7 +366,7 @@ ZigbeeAdapter ZigbeeManager::createAdapterFromUartAdapter(const ZigbeeUartAdapte adapter.setBackendType(ZigbeeAdapter::ZigbeeBackendTypeNxp); break; default: - qCWarning(dcZigbee()) << "Unhandled backend type" << uartAdapter.suggestedZigbeeBackendType() << "which is not implemented in nymea yet."; + qCWarning(dcZigbee()) << "Unhandled backend type" << uartAdapter.zigbeeBackend() << "which is not implemented in nymea yet."; break; } return adapter; diff --git a/libnymea-core/zigbee/zigbeemanager.h b/libnymea-core/zigbee/zigbeemanager.h index d75e9a9a..d01d8053 100644 --- a/libnymea-core/zigbee/zigbeemanager.h +++ b/libnymea-core/zigbee/zigbeemanager.h @@ -57,7 +57,8 @@ public: ZigbeeErrorNoError, ZigbeeErrorAdapterNotAvailable, ZigbeeErrorAdapterAlreadyInUse, - ZigbeeErrorNetworkUuidNotFound + ZigbeeErrorNetworkUuidNotFound, + ZigbeeErrorNetworkOffline }; Q_ENUM(ZigbeeError) @@ -71,6 +72,8 @@ public: ZigbeeError createZigbeeNetwork(const ZigbeeAdapter &adapter, const ZigbeeChannelMask channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels)); ZigbeeError removeZigbeeNetwork(const QUuid &networkUuid); + ZigbeeError setZigbeeNetworkPermitJoin(const QUuid &networkUuid, quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, int duration = 120); + ZigbeeError factoryResetNetwork(const QUuid &networkUuid); private: ZigbeeAdapters m_adapters; @@ -83,7 +86,7 @@ private: ZigbeeNetwork *buildNetworkObject(const QUuid &networkId, ZigbeeAdapter::ZigbeeBackendType backendType); void addNetwork(ZigbeeNetwork *network); - ZigbeeAdapter createAdapterFromUartAdapter(const ZigbeeUartAdapter &uartAdapter); + ZigbeeAdapter convertUartAdapterToAdapter(const ZigbeeUartAdapter &uartAdapter); signals: void availableAdapterAdded(const ZigbeeAdapter &adapter);