/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 Lesser General Public License Usage * Alternatively, this project may be redistributed and/or modified under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "zigbeehandler.h" #include "zigbee/zigbeemanager.h" #include "zigbee/zigbeeadapters.h" #include "loggingcategories.h" #include namespace nymeaserver { ZigbeeHandler::ZigbeeHandler(ZigbeeManager *zigbeeManager, QObject *parent) : JsonHandler(parent), m_zigbeeManager(zigbeeManager) { qRegisterMetaType(); registerEnum(); registerEnum(); registerObject(); // Network object describing a network instance QVariantMap zigbeeNetworkDescription; zigbeeNetworkDescription.insert("networkUuid", enumValueName(Uuid)); zigbeeNetworkDescription.insert("enabled", enumValueName(Bool)); 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)); zigbeeNetworkDescription.insert("permitJoiningEnabled", enumValueName(Bool)); zigbeeNetworkDescription.insert("permitJoiningDuration", enumValueName(Uint)); zigbeeNetworkDescription.insert("permitJoiningRemaining", enumValueName(Uint)); zigbeeNetworkDescription.insert("backend", enumValueName(String)); zigbeeNetworkDescription.insert("networkState", enumRef()); registerObject("ZigbeeNetwork", zigbeeNetworkDescription); QVariantMap params, returns; QString description; // GetAvailableBackends params.clear(); returns.clear(); description = "Get the list of available ZigBee backends."; returns.insert("backends", QVariantList() << enumValueName(String)); registerMethod("GetAvailableBackends", description, params, returns); // GetAdapters params.clear(); returns.clear(); description = "Get the list of available ZigBee adapters and serial ports in order to set up the ZigBee network " "on the desired interface. The \'serialPort\' property can be used as unique identifier for an adapter. " "If an adapter hardware has been recognized as a well known ZigBee adapter, " "the \'hardwareRecognized\' property will be true and the \'baudRate\' and \'backend\' " "configurations can be used as they where given, otherwise the user might set the backend " "and baud rate manually. The available backends can be fetched using the GetAvailableBackends method."; returns.insert("adapters", objectRef()); registerMethod("GetAdapters", description, params, returns); // AdapterAdded notification params.clear(); description = "Emitted whenever a new ZigBee adapter or serial port has been detected in the system."; params.insert("adapter", objectRef()); registerNotification("AdapterAdded", description, params); // AdapterRemoved notification params.clear(); description = "Emitted whenever a ZigBee adapter or serial port has been removed from the system (i.e. unplugged)."; params.insert("adapter", objectRef()); registerNotification("AdapterRemoved", description, params); // GetNetworks params.clear(); returns.clear(); description = "Returns the list of configured ZigBee networks 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 \'serialPort\', \'baudRate\' and \'backend\'. " "The serial ports can be fetched from the available adapters. See \'GetAdapters\' for more information. " "The available backends can be fetched using the \'GetAvailableBackends\' method."; params.insert("serialPort", enumValueName(String)); params.insert("baudRate", enumValueName(Uint)); params.insert("backend", enumValueName(String)); returns.insert("zigbeeError", enumRef()); returns.insert("o:networkUuid", enumValueName(Uuid)); 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("zigbeeNetwork", 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("zigbeeNetwork", 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."; 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. " "The duration value has to be between 0 and 255 seconds. The \'permitJoinDuration\' property of ZigBee network " "object indicates how long permit has been enabled and the \'permitJoiningRemaining\' indicates the rest of the time. " "Those values can be used to show a countdown or progressbar. This method can be recalled for resetting the timeout. " "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 specific router will " "be able to allow new nodes to join the network. A new node will join to the router with the best link quality index (LQI)."; params.insert("networkUuid", enumValueName(Uuid)); params.insert("duration", 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; params.insert("adapter", pack(adapter)); emit AdapterAdded(params); }); connect(m_zigbeeManager, &ZigbeeManager::availableAdapterRemoved, this, [this](const ZigbeeAdapter &adapter){ QVariantMap params; params.insert("adapter", pack(adapter)); emit AdapterRemoved(params); }); connect(m_zigbeeManager, &ZigbeeManager::zigbeeNetworkAdded, this, [this](ZigbeeNetwork *network){ QVariantMap params; params.insert("zigbeeNetwork", packNetwork(network)); emit NetworkAdded(params); }); 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); emit NetworkRemoved(params); }); } QString ZigbeeHandler::name() const { return "Zigbee"; } JsonReply *ZigbeeHandler::GetAvailableBackends(const QVariantMap ¶ms) { Q_UNUSED(params) QVariantMap returnMap; QVariantList backendsList; foreach (const QString &backendName, ZigbeeAdapter::backendNames().values()) backendsList << backendName; returnMap.insert("backends", backendsList); return createReply(returnMap); } JsonReply *ZigbeeHandler::GetAdapters(const QVariantMap ¶ms) { Q_UNUSED(params) QVariantMap returnMap; QVariantList adapterList; foreach (const ZigbeeAdapter &adapter, m_zigbeeManager->availableAdapters()) { adapterList << pack(adapter); } returnMap.insert("adapters", adapterList); return createReply(returnMap); } JsonReply *ZigbeeHandler::AddNetwork(const QVariantMap ¶ms) { QVariantMap returnMap; QString serialPort = params.value("serialPort").toString(); uint baudRate = params.value("baudRate").toUInt(); QString backendString = params.value("backend").toString(); if (!ZigbeeAdapter::backendNames().values().contains(backendString)) { returnMap.insert("zigbeeError", enumValueName(ZigbeeManager::ZigbeeErrorUnknownBackend)); return createReply(returnMap); } QPair result = m_zigbeeManager->createZigbeeNetwork(serialPort, baudRate, ZigbeeAdapter::backendNames().key(backendString)); if (result.first == ZigbeeManager::ZigbeeErrorNoError) { returnMap.insert("networkUuid", result.second); } returnMap.insert("zigbeeError", enumValueName(result.first)); 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::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) 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("enabled", true); // FIXME: set actual value once supported 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()); networkMap.insert("permitJoiningEnabled", network->permitJoiningEnabled()); networkMap.insert("permitJoiningDuration", network->permitJoiningDuration()); networkMap.insert("permitJoiningRemaining", network->permitJoiningRemaining()); switch (network->backendType()) { case Zigbee::ZigbeeBackendTypeDeconz: networkMap.insert("backend", ZigbeeAdapter::backendNames().value(ZigbeeAdapter::ZigbeeBackendTypeDeconz)); break; case Zigbee::ZigbeeBackendTypeNxp: networkMap.insert("backend", ZigbeeAdapter::backendNames().value(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; } }