From bd506ea27fd44cb53b739f89eefdd54665f19833 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 6 Jun 2019 02:57:34 +0200 Subject: [PATCH] Add support for device settings --- .../configuration/networkmanager.cpp | 6 +- libnymea-app-core/devicemanager.cpp | 30 +++++++++- libnymea-app-core/devicemanager.h | 1 + libnymea-app-core/jsonrpc/jsontypes.cpp | 22 +++++++- libnymea-common/types/device.cpp | 28 ++++++++++ libnymea-common/types/device.h | 6 ++ libnymea-common/types/deviceclass.cpp | 29 ++++++++++ libnymea-common/types/deviceclass.h | 16 ++++-- libnymea-common/types/params.cpp | 5 +- .../ui/components/SwipeDelegateGroup.qml | 6 +- .../thingconfiguration/ConfigureThingPage.qml | 55 +++++++++++++++++++ 11 files changed, 188 insertions(+), 16 deletions(-) diff --git a/libnymea-app-core/configuration/networkmanager.cpp b/libnymea-app-core/configuration/networkmanager.cpp index 4bbd4b72..dddf7d65 100644 --- a/libnymea-app-core/configuration/networkmanager.cpp +++ b/libnymea-app-core/configuration/networkmanager.cpp @@ -27,7 +27,7 @@ void NetworkManager::init() { m_jsonClient->sendCommand("NetworkManager.GetNetworkStatus", QVariantMap(), this, "getStatusReply"); m_jsonClient->sendCommand("NetworkManager.GetNetworkDevices", QVariantMap(), this, "getDevicesReply"); - m_jsonClient->sendCommand("NetworkManager.GetWirelessAccessPoints", QVariantMap(), this, "getAccessPointsReply"); +// m_jsonClient->sendCommand("NetworkManager.GetWirelessAccessPoints", QVariantMap(), this, "getAccessPointsReply"); } NetworkManager::NetworkManagerState NetworkManager::state() const @@ -95,7 +95,7 @@ void NetworkManager::disconnectInterface(const QString &interface) void NetworkManager::getStatusReply(const QVariantMap ¶ms) { - qDebug() << "NetworkManager reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); +// qDebug() << "NetworkManager reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); QVariantMap statusMap = params.value("params").toMap().value("status").toMap(); @@ -120,7 +120,7 @@ void NetworkManager::getStatusReply(const QVariantMap ¶ms) void NetworkManager::getDevicesReply(const QVariantMap ¶ms) { - qDebug() << "Dwvices reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); +// qDebug() << "Devices reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); foreach (const QVariant &deviceVariant, params.value("params").toMap().value("wiredNetworkDevices").toList()) { QVariantMap deviceMap = deviceVariant.toMap(); diff --git a/libnymea-app-core/devicemanager.cpp b/libnymea-app-core/devicemanager.cpp index 58e41e52..07dcb704 100644 --- a/libnymea-app-core/devicemanager.cpp +++ b/libnymea-app-core/devicemanager.cpp @@ -93,7 +93,7 @@ void DeviceManager::notificationReceived(const QVariantMap &data) { QString notification = data.value("notification").toString(); if (notification == "Devices.StateChanged") { -// qDebug() << "Device state changed" << data.value("params"); + qDebug() << "Device state changed" << data.value("params"); Device *dev = m_devices->getDevice(data.value("params").toMap().value("deviceId").toUuid()); if (!dev) { qWarning() << "Device state change notification received for an unknown device"; @@ -132,6 +132,22 @@ void DeviceManager::notificationReceived(const QVariantMap &data) return; } qDebug() << "*** device unpacked" << oldDevice->stateValue("98e4476f-e745-4a7f-b795-19269cb70c40"); + } else if (notification == "Devices.DeviceSettingChanged") { + QUuid deviceId = data.value("params").toMap().value("deviceId").toUuid(); + QString paramTypeId = data.value("params").toMap().value("paramTypeId").toString(); + QVariant value = data.value("params").toMap().value("value"); + qDebug() << "Device settings changed notification for device" << deviceId << data.value("params").toMap().value("settings").toList(); + Device *dev = m_devices->getDevice(deviceId); + if (!dev) { + qWarning() << "Device settings changed notification for a device we don't know" << deviceId.toString(); + return; + } + Param *p = dev->settings()->getParam(paramTypeId); + if (!p) { + qWarning() << "Device" << dev->name() << dev->id().toString() << "does not have a setting of id" << paramTypeId; + return; + } + p->setValue(value); } else { qWarning() << "DeviceManager unhandled device notification received" << notification; } @@ -239,9 +255,9 @@ void DeviceManager::getConfiguredDevicesResponse(const QVariantMap ¶ms) device->setStateValue(stateTypeId, value); // qDebug() << "Set device state value:" << device->stateValue(stateTypeId) << value; } -// qDebug() << "Configured Device JSON:" << qUtf8Printable(QJsonDocument::fromVariant(deviceVariant).toJson(QJsonDocument::Indented)); + qDebug() << "Configured Device JSON:" << qUtf8Printable(QJsonDocument::fromVariant(deviceVariant).toJson(QJsonDocument::Indented)); devices()->addDevice(device); -// qDebug() << "*** Added device:" << endl << device; + qDebug() << "*** Added device:" << endl << device; } } m_fetchingData = false; @@ -373,6 +389,14 @@ void DeviceManager::editDevice(const QUuid &deviceId, const QString &name) m_jsonClient->sendCommand("Devices.EditDevice", params, this, "editDeviceResponse"); } +void DeviceManager::setDeviceSettings(const QUuid &deviceId, const QVariantList &settings) +{ + QVariantMap params; + params.insert("deviceId", deviceId); + params.insert("settings", settings); + m_jsonClient->sendCommand("Devices.SetDeviceSettings", params); +} + void DeviceManager::reconfigureDevice(const QUuid &deviceId, const QVariantList &deviceParams) { QVariantMap params; diff --git a/libnymea-app-core/devicemanager.h b/libnymea-app-core/devicemanager.h index 2b4fa8cd..6257a770 100644 --- a/libnymea-app-core/devicemanager.h +++ b/libnymea-app-core/devicemanager.h @@ -69,6 +69,7 @@ public: Q_INVOKABLE void confirmPairing(const QUuid &pairingTransactionId, const QString &secret = QString()); Q_INVOKABLE void removeDevice(const QUuid &deviceId, RemovePolicy policy = RemovePolicyNone); Q_INVOKABLE void editDevice(const QUuid &deviceId, const QString &name); + Q_INVOKABLE void setDeviceSettings(const QUuid &deviceId, const QVariantList &settings); Q_INVOKABLE void reconfigureDevice(const QUuid &deviceId, const QVariantList &deviceParams); Q_INVOKABLE void reconfigureDiscoveredDevice(const QUuid &deviceId, const QUuid &deviceDescriptorId); Q_INVOKABLE int executeAction(const QUuid &deviceId, const QUuid &actionTypeId, const QVariantList ¶ms = QVariantList()); diff --git a/libnymea-app-core/jsonrpc/jsontypes.cpp b/libnymea-app-core/jsonrpc/jsontypes.cpp index 55d3461a..9c56b2dc 100644 --- a/libnymea-app-core/jsonrpc/jsontypes.cpp +++ b/libnymea-app-core/jsonrpc/jsontypes.cpp @@ -91,6 +91,13 @@ DeviceClass *JsonTypes::unpackDeviceClass(const QVariantMap &deviceClassMap, QOb } deviceClass->setParamTypes(paramTypes); + // SettingsTypes + ParamTypes *settingsTypes = new ParamTypes(deviceClass); + foreach (QVariant settingsType, deviceClassMap.value("settingsTypes").toList()) { + settingsTypes->addParamType(JsonTypes::unpackParamType(settingsType.toMap(), settingsTypes)); + } + deviceClass->setSettingsTypes(settingsTypes); + // discovery ParamTypes ParamTypes *discoveryParamTypes = new ParamTypes(deviceClass); foreach (QVariant paramType, deviceClassMap.value("discoveryParamTypes").toList()) { @@ -219,7 +226,6 @@ Device* JsonTypes::unpackDevice(const QVariantMap &deviceMap, DeviceClasses *dev Params *params = device->params(); if (!params) { params = new Params(device); - device->setParams(params); } foreach (QVariant param, deviceMap.value("params").toList()) { Param *p = params->getParam(param.toMap().value("paramTypeId").toString()); @@ -231,6 +237,20 @@ Device* JsonTypes::unpackDevice(const QVariantMap &deviceMap, DeviceClasses *dev } device->setParams(params); + Params *settings = device->settings(); + if (!settings) { + settings = new Params(device); + } + foreach (QVariant setting, deviceMap.value("settings").toList()) { + Param *p = settings->getParam(setting.toMap().value("paramTypeId").toString()); + if (!p) { + p = new Param(); + settings->addParam(p); + } + JsonTypes::unpackParam(setting.toMap(), p); + } + device->setSettings(settings); + States *states = device->states(); if (!states) { states = new States(device); diff --git a/libnymea-common/types/device.cpp b/libnymea-common/types/device.cpp index 06511d2e..29f400e1 100644 --- a/libnymea-common/types/device.cpp +++ b/libnymea-common/types/device.cpp @@ -79,11 +79,29 @@ void Device::setParams(Params *params) if (m_params) { m_params->deleteLater(); } + params->setParent(this); m_params = params; emit paramsChanged(); } } +Params *Device::settings() const +{ + return m_settings; +} + +void Device::setSettings(Params *settings) +{ + if (m_settings != settings) { + if (m_settings) { + m_settings->deleteLater(); + } + settings->setParent(this); + m_settings = settings; + emit settingsChanged(); + } +} + States *Device::states() const { return m_states; @@ -95,6 +113,7 @@ void Device::setStates(States *states) if (m_states) { m_states->deleteLater(); } + states->setParent(this); m_states = states; emit statesChanged(); } @@ -147,6 +166,15 @@ QDebug operator<<(QDebug &dbg, Device *device) dbg << " Param " << i << ": " << pt->id().toString() << ": " << pt->name() << " = " << "*** Unknown value ***" << endl; } } + for (int i = 0; i < device->deviceClass()->settingsTypes()->rowCount(); i++) { + ParamType *pt = device->deviceClass()->settingsTypes()->get(i); + Param *p = device->settings()->getParam(pt->id().toString()); + if (p) { + dbg << " Setting " << i << ": " << pt->id().toString() << ": " << pt->name() << " = " << p->value() << endl; + } else { + dbg << " Setting " << i << ": " << pt->id().toString() << ": " << pt->name() << " = " << "*** Unknown value ***" << endl; + } + } for (int i = 0; i < device->deviceClass()->stateTypes()->rowCount(); i++) { StateType *st = device->deviceClass()->stateTypes()->get(i); State *s = device->states()->getState(st->id()); diff --git a/libnymea-common/types/device.h b/libnymea-common/types/device.h index bc7e59de..e5617f32 100644 --- a/libnymea-common/types/device.h +++ b/libnymea-common/types/device.h @@ -40,6 +40,7 @@ class Device : public QObject Q_PROPERTY(QString name READ name NOTIFY nameChanged) Q_PROPERTY(bool setupComplete READ setupComplete NOTIFY setupCompleteChanged) Q_PROPERTY(Params *params READ params NOTIFY paramsChanged) + Q_PROPERTY(Params *settings READ settings NOTIFY settingsChanged) Q_PROPERTY(States *states READ states NOTIFY statesChanged) Q_PROPERTY(DeviceClass *deviceClass READ deviceClass CONSTANT) @@ -60,6 +61,9 @@ public: Params *params() const; void setParams(Params *params); + Params *settings() const; + void setSettings(Params *settings); + States *states() const; void setStates(States *states); @@ -75,6 +79,7 @@ private: QUuid m_id; bool m_setupComplete; Params *m_params = nullptr; + Params *m_settings = nullptr; States *m_states = nullptr; DeviceClass *m_deviceClass = nullptr; @@ -83,6 +88,7 @@ signals: void nameChanged(); void setupCompleteChanged(); void paramsChanged(); + void settingsChanged(); void statesChanged(); }; diff --git a/libnymea-common/types/deviceclass.cpp b/libnymea-common/types/deviceclass.cpp index ec77e279..e541d1fb 100644 --- a/libnymea-common/types/deviceclass.cpp +++ b/libnymea-common/types/deviceclass.cpp @@ -174,10 +174,27 @@ ParamTypes *DeviceClass::paramTypes() const void DeviceClass::setParamTypes(ParamTypes *paramTypes) { + if (m_paramTypes) { + m_paramTypes->deleteLater(); + } m_paramTypes = paramTypes; emit paramTypesChanged(); } +ParamTypes *DeviceClass::settingsTypes() const +{ + return m_settingsTypes; +} + +void DeviceClass::setSettingsTypes(ParamTypes *settingsTypes) +{ + if (m_settingsTypes) { + m_settingsTypes->deleteLater(); + } + m_settingsTypes = settingsTypes; + emit settingsTypesChanged(); +} + ParamTypes *DeviceClass::discoveryParamTypes() const { return m_discoveryParamTypes; @@ -185,6 +202,9 @@ ParamTypes *DeviceClass::discoveryParamTypes() const void DeviceClass::setDiscoveryParamTypes(ParamTypes *paramTypes) { + if (m_discoveryParamTypes) { + m_discoveryParamTypes->deleteLater(); + } m_discoveryParamTypes = paramTypes; emit discoveryParamTypesChanged(); } @@ -196,6 +216,9 @@ StateTypes *DeviceClass::stateTypes() const void DeviceClass::setStateTypes(StateTypes *stateTypes) { + if (m_stateTypes) { + m_stateTypes->deleteLater(); + } m_stateTypes = stateTypes; emit stateTypesChanged(); } @@ -207,6 +230,9 @@ EventTypes *DeviceClass::eventTypes() const void DeviceClass::setEventTypes(EventTypes *eventTypes) { + if (m_eventTypes) { + m_eventTypes->deleteLater(); + } m_eventTypes = eventTypes; emit eventTypesChanged(); } @@ -218,6 +244,9 @@ ActionTypes *DeviceClass::actionTypes() const void DeviceClass::setActionTypes(ActionTypes *actionTypes) { + if (m_actionTypes) { + m_actionTypes->deleteLater(); + } m_actionTypes = actionTypes; emit actionTypesChanged(); } diff --git a/libnymea-common/types/deviceclass.h b/libnymea-common/types/deviceclass.h index ff819ca4..21ccb3f7 100644 --- a/libnymea-common/types/deviceclass.h +++ b/libnymea-common/types/deviceclass.h @@ -47,6 +47,7 @@ class DeviceClass : public QObject Q_PROPERTY(QStringList interfaces READ interfaces CONSTANT) Q_PROPERTY(QString baseInterface READ baseInterface CONSTANT) Q_PROPERTY(ParamTypes *paramTypes READ paramTypes NOTIFY paramTypesChanged) + Q_PROPERTY(ParamTypes *settingsTypes READ settingsTypes NOTIFY settingsTypesChanged) Q_PROPERTY(ParamTypes *discoveryParamTypes READ discoveryParamTypes NOTIFY discoveryParamTypesChanged) Q_PROPERTY(StateTypes *stateTypes READ stateTypes NOTIFY stateTypesChanged) Q_PROPERTY(EventTypes *eventTypes READ eventTypes NOTIFY eventTypesChanged) @@ -93,6 +94,9 @@ public: ParamTypes *paramTypes() const; void setParamTypes(ParamTypes *paramTypes); + ParamTypes *settingsTypes() const; + void setSettingsTypes(ParamTypes *settingsTypes); + ParamTypes *discoveryParamTypes() const; void setDiscoveryParamTypes(ParamTypes *paramTypes); @@ -117,14 +121,16 @@ private: SetupMethod m_setupMethod; QStringList m_interfaces; - ParamTypes *m_paramTypes; - ParamTypes *m_discoveryParamTypes; - StateTypes *m_stateTypes; - EventTypes *m_eventTypes; - ActionTypes *m_actionTypes; + ParamTypes *m_paramTypes = nullptr; + ParamTypes *m_settingsTypes = nullptr; + ParamTypes *m_discoveryParamTypes = nullptr; + StateTypes *m_stateTypes = nullptr; + EventTypes *m_eventTypes = nullptr; + ActionTypes *m_actionTypes = nullptr; signals: void paramTypesChanged(); + void settingsTypesChanged(); void discoveryParamTypesChanged(); void stateTypesChanged(); void eventTypesChanged(); diff --git a/libnymea-common/types/params.cpp b/libnymea-common/types/params.cpp index f4279c39..339afdc8 100644 --- a/libnymea-common/types/params.cpp +++ b/libnymea-common/types/params.cpp @@ -41,6 +41,9 @@ int Params::count() const Param *Params::get(int index) const { + if (index < 0 || index >= m_params.count()) { + return nullptr; + } return m_params.at(index); } @@ -51,7 +54,7 @@ Param *Params::getParam(QString paramTypeId) const return param; } } - return 0; + return nullptr; } int Params::paramCount() const diff --git a/nymea-app/ui/components/SwipeDelegateGroup.qml b/nymea-app/ui/components/SwipeDelegateGroup.qml index 209e945e..7b2bf720 100644 --- a/nymea-app/ui/components/SwipeDelegateGroup.qml +++ b/nymea-app/ui/components/SwipeDelegateGroup.qml @@ -19,13 +19,13 @@ Item { if (d.delegateCache.indexOf(thisItem) < 0) { d.delegateCache.push(thisItem); - print("cache is now", d.delegateCache.length) +// print("cache is now", d.delegateCache.length) thisItem.Component.destruction.connect(function() { - print("item destroyed", thisItem) +// print("item destroyed", thisItem) var idx = d.delegateCache.indexOf(thisItem) d.delegateCache.splice(idx, 1) - print("cache is now", d.delegateCache.length) +// print("cache is now", d.delegateCache.length) }) thisItem.swipe.opened.connect(function() { diff --git a/nymea-app/ui/thingconfiguration/ConfigureThingPage.qml b/nymea-app/ui/thingconfiguration/ConfigureThingPage.qml index d2ac5435..057401ec 100644 --- a/nymea-app/ui/thingconfiguration/ConfigureThingPage.qml +++ b/nymea-app/ui/thingconfiguration/ConfigureThingPage.qml @@ -119,6 +119,61 @@ Page { } } + Label { + Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + Layout.topMargin: app.margins + text: qsTr("Thing settings") + color: app.accentColor + visible: root.deviceClass.settingsTypes.count > 0 + } + + Repeater { + id: settingsRepeater + model: root.device.settings + delegate: ParamDelegate { + Layout.fillWidth: true + paramType: root.deviceClass.settingsTypes.getParamType(model.id) + value: root.device.settings.get(index).value + writable: true + property bool dirty: root.device.settings.get(index).value !== value + onDirtyChanged: settingsRepeater.checkDirty() + } + function checkDirty() { + for (var i = 0; i < settingsRepeater.count; i++) { + if (settingsRepeater.itemAt(i).dirty) { + dirty = true; + return; + } + } + dirty = false; + } + property bool dirty: false + } + Button { + Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + text: qsTr("Apply") + visible: settingsRepeater.dirty + + onClicked: { + var params = [] + for (var i = 0; i < settingsRepeater.count; i++) { + if (!settingsRepeater.itemAt(i).dirty) { + continue; + } + var setting = {} + setting["paramTypeId"] = settingsRepeater.itemAt(i).param.paramTypeId + setting["value"] = settingsRepeater.itemAt(i).param.value + params.push(setting) + } + + engine.deviceManager.setDeviceSettings(root.device.id, params); + } + } + // ThinDivider {} }