// SPDX-License-Identifier: LGPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of nymea. * * nymea is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * nymea is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with nymea. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "zwavehardwareresourceimplementation.h" #include "zwave/zwavemanager.h" #include "zwave/zwavenetwork.h" #include "loggingcategories.h" Q_DECLARE_LOGGING_CATEGORY(dcZWave) namespace nymeaserver { ZWaveHardwareResourceImplementation::ZWaveHardwareResourceImplementation(ZWaveManager *zwaveManager, QObject *parent): ZWaveHardwareResource(parent), m_zwaveManager(zwaveManager) { connect(m_zwaveManager, &ZWaveManager::networkStateChanged, this, &ZWaveHardwareResourceImplementation::onNetworkStateChanged); connect(m_zwaveManager, &ZWaveManager::nodeInitialized, this, &ZWaveHardwareResourceImplementation::onNodeInitialized); connect(m_zwaveManager, &ZWaveManager::nodeRemoved, this, &ZWaveHardwareResourceImplementation::onNodeRemoved); // connect(m_zigbeeManager, &ZigbeeManager::availableChanged, this, &ZigbeeHardwareResourceImplementation::onZigbeeAvailableChanged); } bool ZWaveHardwareResourceImplementation::available() const { return m_zwaveManager->available(); } bool ZWaveHardwareResourceImplementation::enabled() const { return m_zwaveManager->enabled(); } void ZWaveHardwareResourceImplementation::setEnabled(bool enabled) { m_zwaveManager->setEnabled(enabled); } void ZWaveHardwareResourceImplementation::registerHandler(ZWaveHandler *handler, HandlerType type) { qCDebug(dcZWave()) << "Registering new Z-Wave handler" << handler->name() << "with type" << type; m_handlers.insert(type, handler); } ZWaveNode *ZWaveHardwareResourceImplementation::claimNode(ZWaveHandler *handler, const QUuid &networkUuid, quint8 nodeId) { if (!m_handlers.values().contains(handler)) { qCWarning(dcZWave()) << "Handler" << handler->name() << "is not registered. Not allowing node to be claimed."; return nullptr; } ZWaveNetwork *network = m_zwaveManager->network(networkUuid); if (!network) { qCWarning(dcZWave()) << "Network" << networkUuid << "not found."; return nullptr; } ZWaveNode *node = network->node(nodeId); if (!node) { qCWarning(dcZWave()) << "Node with ID" << nodeId << "not found in ZWave network" << networkUuid.toString(); return nullptr; } if (m_nodeHandlers.contains(node) && m_nodeHandlers.value(node) != handler) { qCWarning(dcZWave()) << "Node with ID" << nodeId << "is already claimed by another handler (" << m_nodeHandlers.value(node)->name() << "). Not allowing node to be reclaimed."; return nullptr; } m_nodeHandlers[node] = handler; return node; } void ZWaveHardwareResourceImplementation::thingsLoaded() { m_thingsLoaded = true; qCDebug(dcZWave) << "Things loaded. Checking for unhandled nodes..."; // We can assume here that all handled nodes have been claimed by plugins // In case we started up and loaded new Z-Wave plugins, let's try to get all previously joined nodes handled now... foreach (ZWaveNetwork *network, m_zwaveManager->networks()) { foreach (ZWaveNode *node, network->nodes()) { // Ignore the controller node if (node->nodeId() == network->controllerNodeId()) continue; if (!m_nodeHandlers.contains(node)) { qCDebug(dcZWave()) << "Node" << node << "is not yet handled by any plugin. Trying to find a suitable plugin."; handleNewNode(node); } } } } void ZWaveHardwareResourceImplementation::onNetworkStateChanged(ZWaveNetwork *network) { // If the network is now ready and things have been loaded already, check if there are // unclaimed nodes that might be handled now. This might happen if a node joins the network // but no appropriate plugin had been installed at the time. If additional plugins have // been installed now, such nodes might be handled by them now. if (network->networkState() == ZWaveNetwork::ZWaveNetworkStateOnline && m_thingsLoaded) { foreach (ZWaveNode *node, network->nodes()) { // Ignore the controller node if (node->nodeId() == network->controllerNodeId()) continue; if (!m_nodeHandlers.contains(node)) { handleNewNode(node); } } } } void ZWaveHardwareResourceImplementation::onNodeInitialized(ZWaveNode *node) { if (!m_thingsLoaded) { return; } handleNewNode(node); } void ZWaveHardwareResourceImplementation::onNodeRemoved(ZWaveNode *node) { qCDebug(dcZWave()) << "Node removed from the network"; ZWaveHandler *handler = m_nodeHandlers.value(node); if (handler) { handler->handleRemoveNode(node); } } void ZWaveHardwareResourceImplementation::handleNewNode(ZWaveNode *node) { ZWaveNetwork *network = m_zwaveManager->network(node->networkUuid()); if (node->nodeId() == network->controllerNodeId()) { // Not forwarding the controller node to plugins... return; } qCDebug(dcZWave()) << "Node" << node->nodeId() << "added to the network:" << node->networkUuid().toString(); ZWaveHandler *handler = nullptr; foreach (ZWaveHandler *tmp, m_handlers) { if (tmp->handleNode(node)) { handler = tmp; m_nodeHandlers.insert(node, handler); qCDebug(dcZWave()) << "Node" << node->nodeId() << "taken by handler" << handler->name(); break; } } if (!handler) { qCInfo(dcZWave()) << "No Z-Wave handler available to handle node" << node; return; } } }