/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 "thingmanager.h" #include "engine.h" #include "types/browseritems.h" #include "types/browseritem.h" #include "thinggroup.h" #include "types/interface.h" #include "types/ioconnections.h" #include #include #include #include #include "logging.h" NYMEA_LOGGING_CATEGORY(dcThingManager, "ThingManager") ThingManager::ThingManager(JsonRpcClient* jsonclient, QObject *parent) : QObject(parent), m_vendors(new Vendors(this)), m_plugins(new Plugins(this)), m_things(new Things(this)), m_thingClasses(new ThingClasses(this)), m_ioConnections(new IOConnections(this)), m_jsonClient(jsonclient) { m_jsonClient->registerNotificationHandler(this, "Integrations", "notificationReceived"); } void ThingManager::clear() { m_things->clearModel(); m_thingClasses->clearModel(); m_vendors->clearModel(); m_plugins->clearModel(); m_ioConnections->clearModel(); } void ThingManager::init() { m_connectionBenchmark = QDateTime::currentDateTime(); m_fetchingData = true; emit fetchingDataChanged(); m_jsonClient->sendCommand("Integrations.GetThingClasses", this, "getThingClassesResponse"); } Vendors *ThingManager::vendors() const { return m_vendors; } Plugins *ThingManager::plugins() const { return m_plugins; } Things *ThingManager::things() const { return m_things; } ThingClasses *ThingManager::thingClasses() const { return m_thingClasses; } IOConnections *ThingManager::ioConnections() const { return m_ioConnections; } bool ThingManager::fetchingData() const { return m_fetchingData; } int ThingManager::addThing(const QUuid &thingClassId, const QString &name, const QVariantList &thingParams) { QVariantMap params; params.insert("thingClassId", thingClassId.toString()); params.insert("name", name); params.insert("thingParams", thingParams); return m_jsonClient->sendCommand("Integrations.AddThing", params, this, "addThingResponse"); } void ThingManager::notificationReceived(const QVariantMap &data) { qCDebug(dcThingManager()) << "ThingManager notifications received:" << qUtf8Printable(QJsonDocument::fromVariant(data).toJson()); QString notification = data.value("notification").toString(); QVariantMap params = data.value("params").toMap(); if (notification == "Integrations.StateChanged") { Thing *thing = m_things->getThing(params.value("thingId").toUuid()); if (!thing) { if (!m_fetchingData) { qCWarning(dcThingManager()) << "Thing state change notification received for an unknown thing"; } return; } QUuid stateTypeId = params.value("stateTypeId").toUuid(); QVariant value = params.value("value"); // qDebug() << "Thing state changed for:" << dev->name() << "State name:" << dev->thingClass()->stateTypes()->getStateType(stateTypeId) << "value:" << value; State *state = thing->state(stateTypeId); state->setValue(value); if (params.contains("minValue")) { state->setMinValue(params.value("minValue")); } if (params.contains("maxValue")) { state->setMaxValue(params.value("maxValue")); } emit thingStateChanged(thing->id(), stateTypeId, value); } else if (notification == "Integrations.ThingAdded") { Thing *thing = unpackThing(this, data.value("params").toMap().value("thing").toMap(), m_thingClasses); if (!thing) { qWarning() << "Cannot parse thing json:" << data; return; } ThingClass *thingClass = thingClasses()->getThingClass(thing->thingClassId()); if (!thingClass) { qCWarning(dcThingManager()) << "Skipping invalid thing. Don't have a thing class for it"; delete thing; return; } qCInfo(dcThingManager()) << "A new thing has been added" << thing->name() << thing->id().toString(); m_things->addThing(thing); emit thingAdded(thing); } else if (notification == "Integrations.ThingRemoved") { QUuid thingId = data.value("params").toMap().value("thingId").toUuid(); // qDebug() << "JsonRpc: Notification: Thing removed" << thingId.toString(); Thing *thing = m_things->getThing(thingId); if (!thing) { qWarning() << "Received a ThingRemoved notification for a thing we don't know!"; return; } m_things->removeThing(thing); emit thingRemoved(thing); thing->deleteLater(); } else if (notification == "Integrations.ThingChanged") { QUuid thingId = data.value("params").toMap().value("thing").toMap().value("id").toUuid(); qCDebug(dcThingManager()) << "Thing changed notification" << thingId << data.value("params").toMap(); Thing *oldThing = m_things->getThing(thingId); if (!oldThing) { qWarning() << "Received a thing changed notification for a thing we don't know"; return; } if (!unpackThing(this, data.value("params").toMap().value("thing").toMap(), m_thingClasses, oldThing)) { qWarning() << "Error parsing thing changed notification" << data; return; } } else if (notification == "Integrations.ThingSettingChanged") { QUuid thingId = data.value("params").toMap().value("thingId").toUuid(); QString paramTypeId = data.value("params").toMap().value("paramTypeId").toString(); QVariant value = data.value("params").toMap().value("value"); // qDebug() << "Thing settings changed notification for thing" << thingId << data.value("params").toMap().value("settings").toList(); Thing *thing = m_things->getThing(thingId); if (!thing) { qWarning() << "Thing settings changed notification for a thing we don't know" << thingId.toString(); return; } Param *p = thing->settings()->getParam(paramTypeId); if (!p) { qWarning() << "Thing" << thing->name() << thing->id().toString() << "does not have a setting of id" << paramTypeId; return; } p->setValue(value); } else if (notification == "Integrations.EventTriggered") { QVariantMap event = data.value("params").toMap().value("event").toMap(); QUuid thingId = event.value("thingId").toUuid(); QUuid eventTypeId = event.value("eventTypeId").toUuid(); Thing *thing = m_things->getThing(thingId); if (!thing) { if (!m_fetchingData) { qCWarning(dcThingManager()) << "received an event from a thing we don't know..." << thingId << qUtf8Printable(QJsonDocument::fromVariant(data).toJson()); } return; } qCDebug(dcThingManager) << "Event received" << thingId.toString() << eventTypeId.toString() << qUtf8Printable(QJsonDocument::fromVariant(event).toJson()); thing->eventTriggered(eventTypeId.toString(), event.value("params").toList()); } else if (notification == "Integrations.IOConnectionAdded") { QVariantMap connectionMap = data.value("params").toMap().value("ioConnection").toMap(); QUuid id = connectionMap.value("id").toUuid(); QUuid inputThingId = connectionMap.value("inputThingId").toUuid(); QUuid inputStateTypeId = connectionMap.value("inputStateTypeId").toUuid(); QUuid outputThingId = connectionMap.value("outputThingId").toUuid(); QUuid outputStateTypeId = connectionMap.value("outputStateTypeId").toUuid(); bool inverted = connectionMap.value("inverted").toBool(); IOConnection *ioConnection = new IOConnection(id, inputThingId, inputStateTypeId, outputThingId, outputStateTypeId, inverted); m_ioConnections->addIOConnection(ioConnection); } else if (notification == "Integrations.IOConnectionRemoved") { QUuid connectionId = data.value("params").toMap().value("ioConnectionId").toUuid(); if (!m_ioConnections->getIOConnection(connectionId)) { qWarning() << "Received an IO connection removed event for an IO connection we don't know."; return; } m_ioConnections->removeIOConnection(connectionId); } else { qWarning() << "ThingManager unhandled thing notification received" << notification; } } void ThingManager::getVendorsResponse(int /*commandId*/, const QVariantMap ¶ms) { // qDebug() << "Got GetSupportedVendors response" << params; if (params.keys().contains("vendors")) { QVariantList vendorList = params.value("vendors").toList(); foreach (QVariant vendorVariant, vendorList) { Vendor *vendor = unpackVendor(vendorVariant.toMap()); m_vendors->addVendor(vendor); // qDebug() << "Added Vendor:" << vendor->name(); } } } void ThingManager::getThingClassesResponse(int /*commandId*/, const QVariantMap ¶ms) { qCDebug(dcThingManager) << "GetThingClasses response:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson()); if (params.keys().contains("thingClasses")) { QVariantList thingClassList = params.value("thingClasses").toList(); foreach (QVariant thingClassVariant, thingClassList) { ThingClass *thingClass = unpackThingClass(thingClassVariant.toMap()); m_thingClasses->addThingClass(thingClass); } } m_jsonClient->sendCommand("Integrations.GetThings", this, "getThingsResponse"); } void ThingManager::getPluginsResponse(int /*commandId*/, const QVariantMap ¶ms) { // qDebug() << "received plugins"; if (params.keys().contains("plugins")) { QVariantList pluginList = params.value("plugins").toList(); foreach (QVariant pluginVariant, pluginList) { Plugin *plugin = unpackPlugin(pluginVariant.toMap(), plugins()); m_plugins->addPlugin(plugin); } } m_jsonClient->sendCommand("Integrations.GetVendors", this, "getVendorsResponse"); } void ThingManager::getThingsResponse(int /*commandId*/, const QVariantMap ¶ms) { // qCritical() << "Things received:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); if (params.keys().contains("things")) { QVariantList thingsList = params.value("things").toList(); QList newThings; foreach (QVariant thingVariant, thingsList) { Thing *thing = unpackThing(this, thingVariant.toMap(), m_thingClasses); if (!thing) { qWarning() << "Error unpacking thing" << thingVariant.toMap().value("name").toString(); continue; } // set initial state values QVariantList stateVariantList = thingVariant.toMap().value("states").toList(); foreach (const QVariant &stateMap, stateVariantList) { QString stateTypeId = stateMap.toMap().value("stateTypeId").toString(); StateType *st = thing->thingClass()->stateTypes()->getStateType(stateTypeId); if (!st) { qWarning() << "Can't find a statetype for this state"; continue; } QVariant value = stateMap.toMap().value("value"); if (st->type() == "Bool") { value.convert(QVariant::Bool); } else if (st->type() == "Double") { value.convert(QVariant::Double); } else if (st->type() == "Int") { value.convert(QVariant::Int); } thing->setStateValue(stateTypeId, value); // qDebug() << "Set thing state value:" << thing->stateValue(stateTypeId) << value; } newThings.append(thing); } things()->addThings(newThings); } qDebug() << "Initializing thing manager took" << m_connectionBenchmark.msecsTo(QDateTime::currentDateTime()) << "ms"; m_fetchingData = false; emit fetchingDataChanged(); m_jsonClient->sendCommand("Integrations.GetIOConnections", this, "getIOConnectionsResponse"); m_jsonClient->sendCommand("Integrations.GetPlugins", this, "getPluginsResponse"); } void ThingManager::addThingResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "Error from string:" << errorFromString(params.value("thingError").toByteArray()) << params.value("thingError"); emit addThingReply(commandId, errorFromString(params.value("thingError").toByteArray()), params.value("thingId").toUuid(), params.value("displayMessage").toString()); if (params.value("thingError").toString() != "ThingErrorNoError") { qWarning() << "Failed to add thing:" << params.value("thingError").toString(); } else if (params.keys().contains("thing")) { QVariantMap thingVariant = params.value("thing").toMap(); Thing *thing = unpackThing(this, thingVariant, m_thingClasses); if (!thing) { qWarning() << "Couldn't parse json in addThingResponse"; return; } qCInfo(dcThingManager()) << "Thing successfully added" << thing->name() << thing->id().toString(); m_things->addThing(thing); } } void ThingManager::removeThingResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "Thing removed response" << params; emit removeThingReply(commandId, errorFromString(params.value("thingError").toByteArray()), params.value("ruleIds").toStringList()); } void ThingManager::pairThingResponse(int commandId, const QVariantMap ¶ms) { emit pairThingReply(commandId, errorFromString(params.value("thingError").toByteArray()), params.value("pairingTransactionId").toUuid(), params.value("setupMethod").toString(), params.value("displayMessage").toString(), params.value("oAuthUrl").toString()); } void ThingManager::confirmPairingResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "ConfirmPairingResponse" << params; emit confirmPairingReply(commandId, errorFromString(params.value("thingError").toByteArray()), params.value("thingId").toUuid(), params.value("displayMessage").toString()); } void ThingManager::setPluginConfigResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "set plugin config response" << params; emit savePluginConfigReply(commandId, errorFromString(params.value("thingError").toByteArray())); } void ThingManager::editThingResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "Edit thing response" << params; emit editThingReply(commandId, errorFromString(params.value("thingError").toByteArray())); } void ThingManager::executeActionResponse(int commandId, const QVariantMap ¶ms) { qCDebug(dcThingManager()) << "Execute Action response" << params; emit executeActionReply(commandId, errorFromString(params.value("thingError").toByteArray()), params.value("displayMessage").toString()); } void ThingManager::reconfigureThingResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "Reconfigure device response" << params; emit reconfigureThingReply(commandId, errorFromString(params.value("thingError").toByteArray()), params.value("displayMessage").toString()); } ThingGroup *ThingManager::createGroup(Interface *interface, ThingsProxy *things) { ThingGroup* group = new ThingGroup(this, interface->createThingClass(), things, this); group->setSetupStatus(Thing::ThingSetupStatusComplete, QString()); return group; } int ThingManager::addDiscoveredThing(const QUuid &thingClassId, const QUuid &thingDescriptorId, const QString &name, const QVariantList &thingParams) { QVariantMap params; params.insert("name", name); params.insert("thingClassId", thingClassId); params.insert("thingDescriptorId", thingDescriptorId.toString()); params.insert("thingParams", thingParams); return m_jsonClient->sendCommand("Integrations.AddThing", params, this, "addThingResponse"); } int ThingManager::pairDiscoveredThing(const QUuid &thingDescriptorId, const QVariantList &thingParams, const QString &name) { QVariantMap params; params.insert("thingDescriptorId", thingDescriptorId.toString()); params.insert("thingParams", thingParams); params.insert("name", name); return m_jsonClient->sendCommand("Integrations.PairThing", params, this, "pairThingResponse"); } int ThingManager::pairThing(const QUuid &thingClassId, const QVariantList &thingParams, const QString &name) { QVariantMap params; params.insert("thingClassId", thingClassId.toString()); params.insert("thingParams", thingParams); params.insert("name", name); return m_jsonClient->sendCommand("Integrations.PairThing", params, this, "pairThingResponse"); } int ThingManager::rePairThing(const QUuid &thingId, const QVariantList &thingParams, const QString &name) { qDebug() << "JsonRpc: pair thing (reconfigure)" << thingId; QVariantMap params; params.insert("thingId", thingId.toString()); params.insert("thingParams", thingParams); if (!name.isEmpty()) { params.insert("name", name); } return m_jsonClient->sendCommand("Integrations.PairThing", params, this, "pairThingResponse"); } int ThingManager::confirmPairing(const QUuid &pairingTransactionId, const QString &secret, const QString &username) { qDebug() << "JsonRpc: confirm pairing" << pairingTransactionId.toString(); QVariantMap params; params.insert("pairingTransactionId", pairingTransactionId.toString()); params.insert("secret", secret); if (!username.isEmpty()) { params.insert("username", username); } return m_jsonClient->sendCommand("Integrations.ConfirmPairing", params, this, "confirmPairingResponse"); } int ThingManager::removeThing(const QUuid &thingId, ThingManager::RemovePolicy policy) { qDebug() << "JsonRpc: remove thing" << thingId.toString(); QVariantMap params; params.insert("thingId", thingId.toString()); if (policy != RemovePolicyNone) { QMetaEnum policyEnum = QMetaEnum::fromType(); params.insert("removePolicy", policyEnum.valueToKey(policy)); } return m_jsonClient->sendCommand("Integrations.RemoveThing", params, this, "removeThingResponse"); } int ThingManager::editThing(const QUuid &thingId, const QString &name) { QVariantMap params; params.insert("thingId", thingId.toString()); params.insert("name", name); return m_jsonClient->sendCommand("Integrations.EditThing", params, this, "editThingResponse"); } int ThingManager::setThingSettings(const QUuid &thingId, const QVariantList &settings) { QVariantMap params; params.insert("thingId", thingId); params.insert("settings", settings); return m_jsonClient->sendCommand("Integrations.SetThingSettings", params); } int ThingManager::reconfigureThing(const QUuid &thingId, const QVariantList &thingParams) { QVariantMap params; params.insert("thingId", thingId.toString()); params.insert("thingParams", thingParams); return m_jsonClient->sendCommand("Integrations.ReconfigureThing", params, this, "reconfigureThingResponse"); } int ThingManager::reconfigureDiscoveredThing(const QUuid &thingDescriptorId, const QVariantList ¶mOverride) { QVariantMap params; params.insert("thingDescriptorId", thingDescriptorId); if (!paramOverride.isEmpty()) { params.insert("thingParams", paramOverride); } return m_jsonClient->sendCommand("Integrations.ReconfigureThing", params, this, "reconfigureThingResponse"); } int ThingManager::executeAction(const QUuid &thingId, const QUuid &actionTypeId, const QVariantList ¶ms) { QVariantMap p; p.insert("thingId", thingId.toString()); p.insert("actionTypeId", actionTypeId.toString()); if (!params.isEmpty()) { p.insert("params", params); } qCDebug(dcThingManager()) << "Executing action" << thingId << actionTypeId; return m_jsonClient->sendCommand("Integrations.ExecuteAction", p, this, "executeActionResponse"); } BrowserItems *ThingManager::browseThing(const QUuid &thingId, const QString &itemId) { QVariantMap params; params.insert("thingId", thingId.toString()); params.insert("itemId", itemId); int id = m_jsonClient->sendCommand("Integrations.BrowseThing", params, this, "browseThingResponse"); // Intentionally not parented. The caller takes ownership and needs to destroy when not needed any more. BrowserItems *itemModel = new BrowserItems(thingId, itemId); itemModel->setBusy(true); QPointer itemModelPtr(itemModel); m_browsingRequests.insert(id, itemModelPtr); return itemModel; } void ThingManager::refreshBrowserItems(BrowserItems *browserItems) { QVariantMap params; params.insert("thingId", browserItems->thingId().toString()); params.insert("itemId", browserItems->itemId()); int id = m_jsonClient->sendCommand("Integrations.BrowseThing", params, this, "browseThingResponse"); // Intentionally not parented. The caller takes ownership and needs to destroy when not needed any more. browserItems->setBusy(true); QPointer itemModelPtr(browserItems); m_browsingRequests.insert(id, browserItems); } BrowserItem *ThingManager::browserItem(const QUuid &thingId, const QString &itemId) { QVariantMap params; params.insert("thingId", thingId.toString()); params.insert("itemId", itemId); int id = m_jsonClient->sendCommand("Integrations.GetBrowserItem", params, this, "browserItemResponse"); // Intentionally not parented. The caller takes ownership and needs to destroy when not needed any more. BrowserItem *item = new BrowserItem(itemId); QPointer itemPtr(item); m_browserDetailsRequests.insert(id, itemPtr); return item; } void ThingManager::browseThingResponse(int commandId, const QVariantMap ¶ms) { // qDebug() << "Browsing response:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); if (!m_browsingRequests.contains(commandId)) { qWarning() << "Received a browsing reply for an id we don't know."; return; } QPointer itemModel = m_browsingRequests.take(commandId); if (!itemModel) { qDebug() << "BrowserItems model seems to have disappeared. Discarding browsing result."; return; } QList itemsToRemove = itemModel->list(); foreach (const QVariant &itemVariant, params.value("items").toList()) { QVariantMap itemMap = itemVariant.toMap(); QString itemId = itemMap.value("id").toString(); BrowserItem *item = itemModel->getBrowserItem(itemId); if (!item) { item = new BrowserItem(itemId, this); itemModel->addBrowserItem(item); } item->setDisplayName(itemMap.value("displayName").toString()); item->setDescription(itemMap.value("description").toString()); item->setIcon(itemMap.value("icon").toString()); item->setThumbnail(itemMap.value("thumbnail").toString()); item->setExecutable(itemMap.value("executable").toBool()); item->setBrowsable(itemMap.value("browsable").toBool()); item->setDisabled(itemMap.value("disabled").toBool()); item->setActionTypeIds(itemMap.value("actionTypeIds").toStringList()); item->setMediaIcon(itemMap.value("mediaIcon").toString()); if (itemsToRemove.contains(item)) { itemsToRemove.removeAll(item); } } while (!itemsToRemove.isEmpty()) { BrowserItem *item = itemsToRemove.takeFirst(); itemModel->removeItem(item); } itemModel->setBusy(false); } void ThingManager::browserItemResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "Browser item details response:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); if (!m_browserDetailsRequests.contains(commandId)) { qWarning() << "Received a browser item details reply for an id we don't know."; return; } QPointer item = m_browserDetailsRequests.take(commandId); if (!item) { qDebug() << "BrowserItem seems to have disappeared. Discarding browser item details result."; return; } QVariantMap itemMap = params.value("item").toMap(); item->setDisplayName(itemMap.value("displayName").toString()); item->setDescription(itemMap.value("description").toString()); item->setIcon(itemMap.value("icon").toString()); item->setThumbnail(itemMap.value("thumbnail").toString()); item->setExecutable(itemMap.value("executable").toBool()); item->setBrowsable(itemMap.value("browsable").toBool()); item->setDisabled(itemMap.value("disabled").toBool()); item->setActionTypeIds(itemMap.value("actionTypeIds").toStringList()); item->setMediaIcon(itemMap.value("mediaIcon").toString()); } int ThingManager::executeBrowserItem(const QUuid &thingId, const QString &itemId) { QVariantMap params; params.insert("thingId", thingId); params.insert("itemId", itemId); return m_jsonClient->sendCommand("Integrations.ExecuteBrowserItem", params, this, "executeBrowserItemResponse"); } void ThingManager::executeBrowserItemResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "Execute Browser Item finished" << params; emit executeBrowserItemReply(commandId, errorFromString(params.value("thingError").toByteArray()), params.value("displayMessage").toString()); } int ThingManager::executeBrowserItemAction(const QUuid &thingId, const QString &itemId, const QUuid &actionTypeId, const QVariantList ¶ms) { QVariantMap data; data.insert("thingId", thingId); data.insert("itemId", itemId); data.insert("actionTypeId", actionTypeId); data.insert("params", params); qDebug() << "params:" << params; return m_jsonClient->sendCommand("Integrations.ExecuteBrowserItemAction", data, this, "executeBrowserItemActionResponse"); } int ThingManager::setStateLogging(const QUuid &thingId, const QUuid &stateTypeId, bool enabled) { return m_jsonClient->sendCommand("Integrations.SetStateLogging", {{"thingId", thingId}, {"stateTypeId", stateTypeId}, {"enabled", enabled}}, this, "setStateLoggingResponse"); } int ThingManager::setActionLogging(const QUuid &thingId, const QUuid &actionTypeId, bool enabled) { return m_jsonClient->sendCommand("Integrations.SetActionLogging", {{"thingId", thingId}, {"actionTypeId", actionTypeId}, {"enabled", enabled}}, this, "setActionLoggingResponse"); } int ThingManager::setEventLogging(const QUuid &thingId, const QUuid &eventTypeId, bool enabled) { return m_jsonClient->sendCommand("Integrations.SetEventLogging", {{"thingId", thingId}, {"eventTypeId", eventTypeId}, {"enabled", enabled}}, this, "setStateLoggingResponse"); } int ThingManager::connectIO(const QUuid &inputThingId, const QUuid &inputStateTypeId, const QUuid &outputThingId, const QUuid &outputStateTypeId, bool inverted) { QVariantMap data; data.insert("inputThingId", inputThingId); data.insert("inputStateTypeId", inputStateTypeId); data.insert("outputThingId", outputThingId); data.insert("outputStateTypeId", outputStateTypeId); data.insert("inverted", inverted); return m_jsonClient->sendCommand("Integrations.ConnectIO", data, this, "connectIOResponse"); } int ThingManager::disconnectIO(const QUuid &ioConnectionId) { QVariantMap data; data.insert("ioConnectionId", ioConnectionId); return m_jsonClient->sendCommand("Integrations.DisconnectIO", data, this, "disconnectIOResponse"); } void ThingManager::executeBrowserItemActionResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "Execute Browser Item Action finished" << params; emit executeBrowserItemActionReply(commandId, errorFromString(params.value("thingError").toByteArray()), params.value("displayMessage").toString()); } void ThingManager::getIOConnectionsResponse(int /*commandId*/, const QVariantMap ¶ms) { // qDebug() << "Get IO connections response" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson()); foreach (const QVariant &connectionVariant, params.value("ioConnections").toList()) { QVariantMap connectionMap = connectionVariant.toMap(); QUuid id = connectionMap.value("id").toUuid(); QUuid inputThingId = connectionMap.value("inputThingId").toUuid(); QUuid inputStateTypeId = connectionMap.value("inputStateTypeId").toUuid(); QUuid outputThingId = connectionMap.value("outputThingId").toUuid(); QUuid outputStateTypeId = connectionMap.value("outputStateTypeId").toUuid(); bool inverted = connectionMap.value("inverted").toBool(); IOConnection *ioConnection = new IOConnection(id, inputThingId, inputStateTypeId, outputThingId, outputStateTypeId, inverted); m_ioConnections->addIOConnection(ioConnection); } } void ThingManager::connectIOResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "ConnectIO response" << commandId << qUtf8Printable(QJsonDocument::fromVariant(params).toJson()); } void ThingManager::disconnectIOResponse(int commandId, const QVariantMap ¶ms) { qDebug() << "DisconnectIO response" << commandId << qUtf8Printable(QJsonDocument::fromVariant(params).toJson()); } void ThingManager::setStateLoggingResponse(int commandId, const QVariantMap ¶ms) { Q_UNUSED(commandId) qCDebug(dcThingManager()) << "Set state logging response" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson()); } void ThingManager::setActionLoggingResponse(int commandId, const QVariantMap ¶ms) { Q_UNUSED(commandId) qCDebug(dcThingManager()) << "Set action logging response" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson()); } void ThingManager::setEventLoggingResponse(int commandId, const QVariantMap ¶ms) { Q_UNUSED(commandId) qCDebug(dcThingManager()) << "Set event logging response" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson()); } Vendor *ThingManager::unpackVendor(const QVariantMap &vendorMap) { Vendor *v = new Vendor(vendorMap.value("id").toString(), vendorMap.value("name").toString()); v->setDisplayName(vendorMap.value("displayName").toString()); return v; } Plugin *ThingManager::unpackPlugin(const QVariantMap &pluginMap, QObject *parent) { Plugin *plugin = new Plugin(parent); plugin->setName(pluginMap.value("name").toString()); plugin->setPluginId(pluginMap.value("id").toUuid()); ParamTypes *paramTypes = new ParamTypes(plugin); foreach (QVariant paramType, pluginMap.value("paramTypes").toList()) { paramTypes->addParamType(unpackParamType(paramType.toMap(), paramTypes)); } plugin->setParamTypes(paramTypes); return plugin; } ThingClass *ThingManager::unpackThingClass(const QVariantMap &thingClassMap) { ThingClass *thingClass = new ThingClass(); thingClass->setName(thingClassMap.value("name").toString()); thingClass->setDisplayName(thingClassMap.value("displayName").toString()); thingClass->setId(thingClassMap.value("id").toUuid()); thingClass->setVendorId(thingClassMap.value("vendorId").toUuid()); thingClass->setBrowsable(thingClassMap.value("browsable").toBool()); QVariantList createMethodsList = thingClassMap.value("createMethods").toList(); QStringList createMethods; foreach (QVariant method, createMethodsList) { createMethods.append(method.toString()); } thingClass->setCreateMethods(createMethods); QMetaEnum metaEnum = QMetaEnum::fromType(); thingClass->setDiscoveryType(static_cast(metaEnum.keyToValue(thingClassMap.value("discoveryType").toByteArray()))); thingClass->setSetupMethod(stringToSetupMethod(thingClassMap.value("setupMethod").toString())); thingClass->setInterfaces(thingClassMap.value("interfaces").toStringList()); thingClass->setProvidedInterfaces(thingClassMap.value("providedInterfaces").toStringList()); // ParamTypes ParamTypes *paramTypes = new ParamTypes(thingClass); foreach (QVariant paramType, thingClassMap.value("paramTypes").toList()) { paramTypes->addParamType(unpackParamType(paramType.toMap(), paramTypes)); } thingClass->setParamTypes(paramTypes); // SettingsTypes ParamTypes *settingsTypes = new ParamTypes(thingClass); foreach (QVariant settingsType, thingClassMap.value("settingsTypes").toList()) { settingsTypes->addParamType(unpackParamType(settingsType.toMap(), settingsTypes)); } thingClass->setSettingsTypes(settingsTypes); // discovery ParamTypes ParamTypes *discoveryParamTypes = new ParamTypes(thingClass); foreach (QVariant paramType, thingClassMap.value("discoveryParamTypes").toList()) { discoveryParamTypes->addParamType(unpackParamType(paramType.toMap(), discoveryParamTypes)); } thingClass->setDiscoveryParamTypes(discoveryParamTypes); // StateTypes StateTypes *stateTypes = new StateTypes(thingClass); foreach (QVariant stateType, thingClassMap.value("stateTypes").toList()) { stateTypes->addStateType(unpackStateType(stateType.toMap(), stateTypes)); } thingClass->setStateTypes(stateTypes); // EventTypes EventTypes *eventTypes = new EventTypes(thingClass); foreach (QVariant eventType, thingClassMap.value("eventTypes").toList()) { eventTypes->addEventType(unpackEventType(eventType.toMap(), eventTypes)); } thingClass->setEventTypes(eventTypes); // ActionTypes ActionTypes *actionTypes = new ActionTypes(thingClass); foreach (QVariant actionType, thingClassMap.value("actionTypes").toList()) { actionTypes->addActionType(unpackActionType(actionType.toMap(), actionTypes)); } thingClass->setActionTypes(actionTypes); // BrowserItemActionTypes ActionTypes *browserItemActionTypes = new ActionTypes(thingClass); foreach (QVariant actionType, thingClassMap.value("browserItemActionTypes").toList()) { browserItemActionTypes->addActionType(unpackActionType(actionType.toMap(), actionTypes)); } thingClass->setBrowserItemActionTypes(browserItemActionTypes); return thingClass; } void ThingManager::unpackParam(const QVariantMap ¶mMap, Param *param) { param->setParamTypeId(paramMap.value("paramTypeId").toString()); param->setValue(paramMap.value("value")); } ParamType *ThingManager::unpackParamType(const QVariantMap ¶mTypeMap, QObject *parent) { ParamType *paramType = new ParamType(parent); paramType->setId(paramTypeMap.value("id").toString()); paramType->setName(paramTypeMap.value("name").toString()); paramType->setDisplayName(paramTypeMap.value("displayName").toString()); paramType->setType(paramTypeMap.value("type").toString()); paramType->setIndex(paramTypeMap.value("index").toInt()); paramType->setDefaultValue(paramTypeMap.value("defaultValue")); paramType->setMinValue(paramTypeMap.value("minValue")); paramType->setMaxValue(paramTypeMap.value("maxValue")); paramType->setAllowedValues(paramTypeMap.value("allowedValues").toList()); paramType->setInputType(stringToInputType(paramTypeMap.value("inputType").toString())); paramType->setReadOnly(paramTypeMap.value("readOnly").toBool()); paramType->setUnit(stringToUnit(paramTypeMap.value("unit").toString())); return paramType; } StateType *ThingManager::unpackStateType(const QVariantMap &stateTypeMap, QObject *parent) { StateType *stateType = new StateType(parent); stateType->setId(stateTypeMap.value("id").toString()); stateType->setName(stateTypeMap.value("name").toString()); stateType->setDisplayName(stateTypeMap.value("displayName").toString()); stateType->setIndex(stateTypeMap.value("index").toInt()); stateType->setDefaultValue(stateTypeMap.value("defaultValue")); stateType->setAllowedValues(stateTypeMap.value("possibleValues").toList()); stateType->setType(stateTypeMap.value("type").toString()); stateType->setMinValue(stateTypeMap.value("minValue")); stateType->setMaxValue(stateTypeMap.value("maxValue")); stateType->setUnit(stringToUnit(stateTypeMap.value("unit").toString())); QMetaEnum metaEnum = QMetaEnum::fromType(); Types::IOType ioType = static_cast(metaEnum.keyToValue(stateTypeMap.value("ioType").toByteArray())); stateType->setIOType(ioType); return stateType; } EventType *ThingManager::unpackEventType(const QVariantMap &eventTypeMap, QObject *parent) { EventType *eventType = new EventType(parent); eventType->setId(eventTypeMap.value("id").toString()); eventType->setName(eventTypeMap.value("name").toString()); eventType->setDisplayName(eventTypeMap.value("displayName").toString()); eventType->setIndex(eventTypeMap.value("index").toInt()); ParamTypes *paramTypes = new ParamTypes(eventType); foreach (QVariant paramType, eventTypeMap.value("paramTypes").toList()) { paramTypes->addParamType(unpackParamType(paramType.toMap(), paramTypes)); } eventType->setParamTypes(paramTypes); return eventType; } ActionType *ThingManager::unpackActionType(const QVariantMap &actionTypeMap, QObject *parent) { ActionType *actionType = new ActionType(parent); actionType->setId(actionTypeMap.value("id").toString()); actionType->setName(actionTypeMap.value("name").toString()); actionType->setDisplayName(actionTypeMap.value("displayName").toString()); actionType->setIndex(actionTypeMap.value("index").toInt()); ParamTypes *paramTypes = new ParamTypes(actionType); foreach (QVariant paramType, actionTypeMap.value("paramTypes").toList()) { paramTypes->addParamType(unpackParamType(paramType.toMap(), paramTypes)); } actionType->setParamTypes(paramTypes); return actionType; } Thing* ThingManager::unpackThing(ThingManager *thingManager, const QVariantMap &thingMap, ThingClasses *thingClasses, Thing *oldThing) { QUuid thingClassId = thingMap.value("thingClassId").toUuid(); ThingClass *thingClass = thingClasses->getThingClass(thingClassId); if (!thingClass) { qWarning() << "Cannot find a thing class for this thing"; return nullptr; } QUuid parentId = thingMap.value("parentId").toUuid(); Thing *thing = nullptr; if (oldThing) { thing = oldThing; } else { thing = new Thing(thingManager, thingClass, parentId); } thing->setName(thingMap.value("name").toString()); thing->setId(thingMap.value("id").toUuid()); // As of JSONRPC 4.2 setupComplete is deprecated and setupStatus is new if (thingMap.contains("setupStatus")) { QString setupStatus = thingMap.value("setupStatus").toString(); QString setupDisplayMessage = thingMap.value("setupDisplayMessage").toString(); if (setupStatus == "ThingSetupStatusNone") { thing->setSetupStatus(Thing::ThingSetupStatusNone, setupDisplayMessage); } else if (setupStatus == "ThingSetupStatusInProgress") { thing->setSetupStatus(Thing::ThingSetupStatusInProgress, setupDisplayMessage); } else if (setupStatus == "ThingSetupStatusComplete") { thing->setSetupStatus(Thing::ThingSetupStatusComplete, setupDisplayMessage); } else if (setupStatus == "ThingSetupStatusFailed") { thing->setSetupStatus(Thing::ThingSetupStatusFailed, setupDisplayMessage); } } else { thing->setSetupStatus(thingMap.value("setupComplete").toBool() ? Thing::ThingSetupStatusComplete : Thing::ThingSetupStatusNone, QString()); } Params *params = thing->params(); if (!params) { params = new Params(thing); } foreach (QVariant param, thingMap.value("params").toList()) { Param *p = params->getParam(param.toMap().value("paramTypeId").toString()); if (!p) { p = new Param(); params->addParam(p); } unpackParam(param.toMap(), p); } thing->setParams(params); Params *settings = thing->settings(); if (!settings) { settings = new Params(thing); } foreach (QVariant setting, thingMap.value("settings").toList()) { Param *p = settings->getParam(setting.toMap().value("paramTypeId").toString()); if (!p) { p = new Param(); settings->addParam(p); } unpackParam(setting.toMap(), p); } thing->setSettings(settings); States *states = thing->states(); if (!states) { states = new States(thing); } foreach (const QVariant &stateVariant, thingMap.value("states").toList()) { QVariantMap stateMap = stateVariant.toMap(); State *state = states->getState(stateMap.value("stateTypeId").toUuid()); if (!state) { state = new State(thing->id(), stateMap.value("stateTypeId").toUuid(), stateMap.value("value"), states); states->addState(state); } else { state->setValue(stateMap.value("value")); } StateType *stateType = thing->thingClass()->stateTypes()->getStateType(state->stateTypeId()); if (stateMap.contains("minValue")) { state->setMinValue(stateMap.value("minValue")); } else { state->setMinValue(stateType->minValue()); } if (stateMap.contains("maxValue")) { state->setMaxValue(stateMap.value("maxValue")); } else { state->setMaxValue(stateType->maxValue()); } } thing->setStates(states); QList loggedStateTypeIds; foreach (const QVariant &uuid, thingMap.value("loggedStateTypeIds").toList()) { loggedStateTypeIds.append(uuid.toUuid()); } thing->setLoggedStateTypeIds(loggedStateTypeIds); QList loggedEventTypeIds; foreach (const QVariant &uuid, thingMap.value("loggedEventTypeIds").toList()) { loggedEventTypeIds.append(uuid.toUuid()); } thing->setLoggedEventTypeIds(loggedEventTypeIds); QList loggedActionTypeIds; foreach (const QVariant &uuid, thingMap.value("loggedActionTypeIds").toList()) { loggedActionTypeIds.append(uuid.toUuid()); } thing->setLoggedActionTypeIds(loggedActionTypeIds); return thing; } QVariantMap ThingManager::packParam(Param *param) { QVariantMap ret; ret.insert("paramTypeId", param->paramTypeId()); ret.insert("value", param->value()); return ret; } Thing::ThingError ThingManager::errorFromString(const QByteArray &thingErrorString) { QMetaEnum metaEnum = QMetaEnum::fromType(); return static_cast(metaEnum.keyToValue(thingErrorString)); } ThingClass::SetupMethod ThingManager::stringToSetupMethod(const QString &setupMethodString) { if (setupMethodString == "SetupMethodJustAdd") { return ThingClass::SetupMethodJustAdd; } else if (setupMethodString == "SetupMethodDisplayPin") { return ThingClass::SetupMethodDisplayPin; } else if (setupMethodString == "SetupMethodEnterPin") { return ThingClass::SetupMethodEnterPin; } else if (setupMethodString == "SetupMethodPushButton") { return ThingClass::SetupMethodPushButton; } else if (setupMethodString == "SetupMethodOAuth") { return ThingClass::SetupMethodOAuth; } else if (setupMethodString == "SetupMethodUserAndPassword") { return ThingClass::SetupMethodUserAndPassword; } return ThingClass::SetupMethodJustAdd; } Types::Unit ThingManager::stringToUnit(const QString &unitString) { QMetaEnum metaEnum = QMetaEnum::fromType(); Types::Unit unit = static_cast(metaEnum.keyToValue(unitString.toUtf8())); return unit; // if (unitString == "UnitNone") { // return QPair(Types::UnitNone, ""); // } else if (unitString == "UnitSeconds") { // return QPair(Types::UnitSeconds, "s"); // } else if (unitString == "UnitMinutes") { // return QPair(Types::UnitMinutes, "m"); // } else if (unitString == "UnitHours") { // return QPair(Types::UnitHours, "h"); // } else if (unitString == "UnitUnixTime") { // return QPair(Types::UnitUnixTime, "datetime"); // } else if (unitString == "UnitMeterPerSecond") { // return QPair(Types::UnitMeterPerSecond, "m/s"); // } else if (unitString == "UnitKiloMeterPerHour") { // return QPair(Types::UnitKiloMeterPerHour, "km/h"); // } else if (unitString == "UnitDegree") { // return QPair(Types::UnitDegree, "°"); // } else if (unitString == "UnitRadiant") { // return QPair(Types::UnitRadiant, "rad"); // } else if (unitString == "UnitDegreeCelsius") { // return QPair(Types::UnitDegreeCelsius, "°C"); // } else if (unitString == "UnitDegreeKelvin") { // return QPair(Types::UnitDegreeKelvin, "°K"); // } else if (unitString == "UnitMired") { // return QPair(Types::UnitMired, "mir"); // } else if (unitString == "UnitMilliBar") { // return QPair(Types::UnitMilliBar, "mbar"); // } else if (unitString == "UnitBar") { // return QPair(Types::UnitBar, "bar"); // } else if (unitString == "UnitPascal") { // return QPair(Types::UnitPascal, "Pa"); // } else if (unitString == "UnitHectoPascal") { // return QPair(Types::UnitHectoPascal, "hPa"); // } else if (unitString == "UnitAtmosphere") { // return QPair(Types::UnitAtmosphere, "atm"); // } else if (unitString == "UnitLumen") { // return QPair(Types::UnitLumen, "lm"); // } else if (unitString == "UnitLux") { // return QPair(Types::UnitLux, "lx"); // } else if (unitString == "UnitCandela") { // return QPair(Types::UnitCandela, "cd"); // } else if (unitString == "UnitMilliMeter") { // return QPair(Types::UnitMilliMeter, "mm"); // } else if (unitString == "UnitCentiMeter") { // return QPair(Types::UnitCentiMeter, "cm"); // } else if (unitString == "UnitMeter") { // return QPair(Types::UnitMeter, "m"); // } else if (unitString == "UnitKiloMeter") { // return QPair(Types::UnitKiloMeter, "km"); // } else if (unitString == "UnitGram") { // return QPair(Types::UnitGram, "g"); // } else if (unitString == "UnitKiloGram") { // return QPair(Types::UnitKiloGram, "kg"); // } else if (unitString == "UnitDezibel") { // return QPair(Types::UnitDezibel, "db"); // } else if (unitString == "UnitBpm") { // return QPair(Types::UnitBpm, "bpm"); // } else if (unitString == "UnitKiloByte") { // return QPair(Types::UnitKiloByte, "kB"); // } else if (unitString == "UnitMegaByte") { // return QPair(Types::UnitMegaByte, "MB"); // } else if (unitString == "UnitGigaByte") { // return QPair(Types::UnitGigaByte, "GB"); // } else if (unitString == "UnitTeraByte") { // return QPair(Types::UnitTeraByte, "TB"); // } else if (unitString == "UnitMilliWatt") { // return QPair(Types::UnitMilliWatt, "mW"); // } else if (unitString == "UnitWatt") { // return QPair(Types::UnitWatt, "W"); // } else if (unitString == "UnitKiloWatt") { // return QPair(Types::UnitKiloWatt, "kW"); // } else if (unitString == "UnitKiloWattHour") { // return QPair(Types::UnitKiloWattHour, "kWh"); // } else if (unitString == "UnitEuroPerMegaWattHour") { // return QPair(Types::UnitEuroPerMegaWattHour, "€/MWh"); // } else if (unitString == "UnitEuroCentPerKiloWattHour") { // return QPair(Types::UnitEuroCentPerKiloWattHour, "ct/kWh"); // } else if (unitString == "UnitPercentage") { // return QPair(Types::UnitPercentage, "%"); // } else if (unitString == "UnitPartsPerMillion") { // return QPair(Types::UnitPartsPerMillion, "ppm"); // } else if (unitString == "UnitEuro") { // return QPair(Types::UnitEuro, "€"); // } else if (unitString == "UnitDollar") { // return QPair(Types::UnitDollar, "$"); // } else if (unitString == "UnitHerz") { // legacy // return QPair(Types::UnitHertz, "Hz"); // } else if (unitString == "UnitHertz") { // return QPair(Types::UnitHertz, "Hz"); // } else if (unitString == "UnitAmpere") { // return QPair(Types::UnitAmpere, "A"); // } else if (unitString == "UnitMilliAmpere") { // return QPair(Types::UnitMilliAmpere, "mA"); // } else if (unitString == "UnitVolt") { // return QPair(Types::UnitVolt, "V"); // } else if (unitString == "UnitMilliVolt") { // return QPair(Types::UnitMilliVolt, "mV"); // } else if (unitString == "UnitVoltAmpere") { // return QPair(Types::UnitVoltAmpere, "VA"); // } else if (unitString == "UnitVoltAmpereReactive") { // return QPair(Types::UnitVoltAmpereReactive, "VAR"); // } else if (unitString == "UnitAmpereHour") { // return QPair(Types::UnitAmpereHour, "Ah"); // } else if (unitString == "UnitMicroSiemensPerCentimeter") { // return QPair(Types::UnitMicroSiemensPerCentimeter, "µS/cm"); // } else if (unitString == "UnitDuration") { // return QPair(Types::UnitDuration, "s"); // } // return QPair(Types::UnitNone, ""); } Types::InputType ThingManager::stringToInputType(const QString &inputTypeString) { if (inputTypeString == "InputTypeNone") { return Types::InputTypeNone; } else if (inputTypeString == "InputTypeTextLine") { return Types::InputTypeTextLine; } else if (inputTypeString == "InputTypeTextArea") { return Types::InputTypeTextArea; } else if (inputTypeString == "InputTypePassword") { return Types::InputTypePassword; } else if (inputTypeString == "InputTypeSearch") { return Types::InputTypeSearch; } else if (inputTypeString == "InputTypeMail") { return Types::InputTypeMail; } else if (inputTypeString == "InputTypeIPv4Address") { return Types::InputTypeIPv4Address; } else if (inputTypeString == "InputTypeIPv6Address") { return Types::InputTypeIPv6Address; } else if (inputTypeString == "InputTypeUrl") { return Types::InputTypeUrl; } else if (inputTypeString == "InputTypeMacAddress") { return Types::InputTypeMacAddress; } return Types::InputTypeNone; }