From 68983e2fec2a09702c49a4cddd75941c035f77b9 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 9 Dec 2020 00:14:34 +0100 Subject: [PATCH] Add a rule template for automatic night mode Also adjusts rule templates filtering to be able to deal with optional states/events/actions in interfaces --- libnymea-app/devicesproxy.cpp | 62 +++++++++ libnymea-app/devicesproxy.h | 20 +++ .../ruletemplates/eventdescriptortemplate.cpp | 8 +- .../ruletemplates/eventdescriptortemplate.h | 8 +- .../ruletemplates/ruleactiontemplate.cpp | 8 +- .../ruletemplates/ruleactiontemplate.h | 8 +- libnymea-app/ruletemplates/ruletemplates.cpp | 124 +++++++++++++++--- libnymea-app/ruletemplates/ruletemplates.h | 5 + .../ruletemplates/statedescriptortemplate.cpp | 8 +- .../ruletemplates/statedescriptortemplate.h | 8 +- nymea-app/ruletemplates/mediatemplates.json | 42 ++++++ nymea-app/ui/Nymea.qml | 1 + nymea-app/ui/magic/NewThingMagicPage.qml | 34 ++--- nymea-app/ui/magic/SelectThingPage.qml | 3 + 14 files changed, 282 insertions(+), 57 deletions(-) diff --git a/libnymea-app/devicesproxy.cpp b/libnymea-app/devicesproxy.cpp index 4da19364..da602766 100644 --- a/libnymea-app/devicesproxy.cpp +++ b/libnymea-app/devicesproxy.cpp @@ -203,6 +203,51 @@ void DevicesProxy::setNameFilter(const QString &nameFilter) } } +QString DevicesProxy::requiredEventName() const +{ + return m_requiredEventName; +} + +void DevicesProxy::setRequiredEventName(const QString &requiredEventName) +{ + if (m_requiredEventName != requiredEventName) { + m_requiredEventName = requiredEventName; + emit requiredEventNameChanged(); + invalidateFilter(); + emit countChanged(); + } +} + +QString DevicesProxy::requiredStateName() const +{ + return m_requiredStateName; +} + +void DevicesProxy::setRequiredStateName(const QString &requiredStateName) +{ + if (m_requiredStateName != requiredStateName) { + m_requiredStateName = requiredStateName; + emit requiredStateNameChanged(); + invalidateFilter(); + emit countChanged(); + } +} + +QString DevicesProxy::requiredActionName() const +{ + return m_requiredActionName; +} + +void DevicesProxy::setRequiredActionName(const QString &requiredActionName) +{ + if (m_requiredActionName != requiredActionName) { + m_requiredActionName = requiredActionName; + emit requiredActionNameChanged(); + invalidateFilter(); + emit countChanged(); + } +} + bool DevicesProxy::showDigitalInputs() const { return m_showDigitalInputs; @@ -489,5 +534,22 @@ bool DevicesProxy::filterAcceptsRow(int source_row, const QModelIndex &source_pa return false; } } + + if (!m_requiredEventName.isEmpty()) { + if (!device->thingClass()->eventTypes()->findByName(m_requiredEventName)) { + return false; + } + } + if (!m_requiredStateName.isEmpty()) { + if (!device->thingClass()->stateTypes()->findByName(m_requiredStateName)) { + return false; + } + } + if (!m_requiredActionName.isEmpty()) { + if (!device->thingClass()->actionTypes()->findByName(m_requiredActionName)) { + return false; + } + } + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } diff --git a/libnymea-app/devicesproxy.h b/libnymea-app/devicesproxy.h index d8a74cf6..4363b00f 100644 --- a/libnymea-app/devicesproxy.h +++ b/libnymea-app/devicesproxy.h @@ -53,6 +53,10 @@ class DevicesProxy : public QSortFilterProxyModel Q_PROPERTY(QStringList hiddenInterfaces READ hiddenInterfaces WRITE setHiddenInterfaces NOTIFY hiddenInterfacesChanged) Q_PROPERTY(QString nameFilter READ nameFilter WRITE setNameFilter NOTIFY nameFilterChanged) + Q_PROPERTY(QString requiredEventName READ requiredEventName WRITE setRequiredEventName NOTIFY requiredEventNameChanged) + Q_PROPERTY(QString requiredStateName READ requiredStateName WRITE setRequiredStateName NOTIFY requiredStateNameChanged) + Q_PROPERTY(QString requiredActionName READ requiredActionName WRITE setRequiredActionName NOTIFY requiredActionNameChanged) + // Setting one of those to true will hide those set to false. If all of those are false no IO filtering will be done Q_PROPERTY(bool showDigitalInputs READ showDigitalInputs WRITE setShowDigitalInputs NOTIFY showDigitalInputsChanged) Q_PROPERTY(bool showDigitalOutputs READ showDigitalOutputs WRITE setShowDigitalOutputs NOTIFY showDigitalOutputsChanged) @@ -101,6 +105,15 @@ public: QString nameFilter() const; void setNameFilter(const QString &nameFilter); + QString requiredEventName() const; + void setRequiredEventName(const QString &requiredEventName); + + QString requiredStateName() const; + void setRequiredStateName(const QString &requiredStateName); + + QString requiredActionName() const; + void setRequiredActionName(const QString &requiredActionName); + bool showDigitalInputs() const; void setShowDigitalInputs(bool showDigitalInputs); @@ -142,6 +155,9 @@ signals: void shownInterfacesChanged(); void hiddenInterfacesChanged(); void nameFilterChanged(); + void requiredEventNameChanged(); + void requiredStateNameChanged(); + void requiredActionNameChanged(); void showDigitalInputsChanged(); void showDigitalOutputsChanged(); void showAnalogInputsChanged(); @@ -166,6 +182,10 @@ private: QStringList m_hiddenInterfaces; QString m_nameFilter; + QString m_requiredEventName; + QString m_requiredStateName; + QString m_requiredActionName; + bool m_showDigitalInputs = false; bool m_showDigitalOutputs = false; bool m_showAnalogInputs = false; diff --git a/libnymea-app/ruletemplates/eventdescriptortemplate.cpp b/libnymea-app/ruletemplates/eventdescriptortemplate.cpp index 48edea0e..1024f6db 100644 --- a/libnymea-app/ruletemplates/eventdescriptortemplate.cpp +++ b/libnymea-app/ruletemplates/eventdescriptortemplate.cpp @@ -30,10 +30,10 @@ #include "eventdescriptortemplate.h" -EventDescriptorTemplate::EventDescriptorTemplate(const QString &interfaceName, const QString &interfaceEvent, int selectionId, SelectionMode selectionMode, QObject *parent): +EventDescriptorTemplate::EventDescriptorTemplate(const QString &interfaceName, const QString &eventName, int selectionId, SelectionMode selectionMode, QObject *parent): QObject(parent), m_interfaceName(interfaceName), - m_interfaceEvent(interfaceEvent), + m_eventName(eventName), m_selectionId(selectionId), m_selectionMode(selectionMode), m_paramDescriptors(new ParamDescriptors(this)) @@ -46,9 +46,9 @@ QString EventDescriptorTemplate::interfaceName() const return m_interfaceName; } -QString EventDescriptorTemplate::interfaceEvent() const +QString EventDescriptorTemplate::eventName() const { - return m_interfaceEvent; + return m_eventName; } int EventDescriptorTemplate::selectionId() const diff --git a/libnymea-app/ruletemplates/eventdescriptortemplate.h b/libnymea-app/ruletemplates/eventdescriptortemplate.h index 9d88bd18..c815a91e 100644 --- a/libnymea-app/ruletemplates/eventdescriptortemplate.h +++ b/libnymea-app/ruletemplates/eventdescriptortemplate.h @@ -38,7 +38,7 @@ class EventDescriptorTemplate : public QObject { Q_OBJECT Q_PROPERTY(QString interfaceName READ interfaceName CONSTANT) - Q_PROPERTY(QString interfaceEvent READ interfaceEvent CONSTANT) + Q_PROPERTY(QString eventName READ eventName CONSTANT) Q_PROPERTY(int selectionId READ selectionId CONSTANT) Q_PROPERTY(SelectionMode selectionMode READ selectionMode CONSTANT) Q_PROPERTY(ParamDescriptors* paramDescriptors READ paramDescriptors CONSTANT) @@ -50,17 +50,17 @@ public: }; Q_ENUM(SelectionMode) - explicit EventDescriptorTemplate(const QString &interfaceName, const QString &interfaceEvent, int selectionId, SelectionMode selectionMode = SelectionModeAny, QObject *parent = nullptr); + explicit EventDescriptorTemplate(const QString &interfaceName, const QString &eventName, int selectionId, SelectionMode selectionMode = SelectionModeAny, QObject *parent = nullptr); QString interfaceName() const; - QString interfaceEvent() const; + QString eventName() const; int selectionId() const; SelectionMode selectionMode() const; ParamDescriptors* paramDescriptors() const; private: QString m_interfaceName; - QString m_interfaceEvent; + QString m_eventName; int m_selectionId = 0; SelectionMode m_selectionMode = SelectionModeAny; ParamDescriptors *m_paramDescriptors = nullptr; diff --git a/libnymea-app/ruletemplates/ruleactiontemplate.cpp b/libnymea-app/ruletemplates/ruleactiontemplate.cpp index d2ba04ac..7741f0de 100644 --- a/libnymea-app/ruletemplates/ruleactiontemplate.cpp +++ b/libnymea-app/ruletemplates/ruleactiontemplate.cpp @@ -31,10 +31,10 @@ #include "ruleactiontemplate.h" #include "ruleactionparamtemplate.h" -RuleActionTemplate::RuleActionTemplate(const QString &interfaceName, const QString &interfaceAction, int selectionId, RuleActionTemplate::SelectionMode selectionMode, RuleActionParamTemplates *params, QObject *parent): +RuleActionTemplate::RuleActionTemplate(const QString &interfaceName, const QString &actionName, int selectionId, RuleActionTemplate::SelectionMode selectionMode, RuleActionParamTemplates *params, QObject *parent): QObject(parent), m_interfaceName(interfaceName), - m_interfaceAction(interfaceAction), + m_actionName(actionName), m_selectionId(selectionId), m_selectionMode(selectionMode), m_ruleActionParamTemplates(params ? params : new RuleActionParamTemplates()) @@ -47,9 +47,9 @@ QString RuleActionTemplate::interfaceName() const return m_interfaceName; } -QString RuleActionTemplate::interfaceAction() const +QString RuleActionTemplate::actionName() const { - return m_interfaceAction; + return m_actionName; } int RuleActionTemplate::selectionId() const diff --git a/libnymea-app/ruletemplates/ruleactiontemplate.h b/libnymea-app/ruletemplates/ruleactiontemplate.h index 197ab75e..f21d120b 100644 --- a/libnymea-app/ruletemplates/ruleactiontemplate.h +++ b/libnymea-app/ruletemplates/ruleactiontemplate.h @@ -39,7 +39,7 @@ class RuleActionTemplate : public QObject { Q_OBJECT Q_PROPERTY(QString interfaceName READ interfaceName CONSTANT) - Q_PROPERTY(QString interfaceAction READ interfaceAction CONSTANT) + Q_PROPERTY(QString actionName READ actionName CONSTANT) Q_PROPERTY(int selectionId READ selectionId CONSTANT) Q_PROPERTY(SelectionMode selectionMode READ selectionMode CONSTANT) Q_PROPERTY(RuleActionParamTemplates* ruleActionParamTemplates READ ruleActionParamTemplates CONSTANT) @@ -53,17 +53,17 @@ public: }; Q_ENUM(SelectionMode) - explicit RuleActionTemplate(const QString &interfaceName, const QString &interfaceAction, int selectionId, SelectionMode selectionMode = SelectionModeAny, RuleActionParamTemplates *params = nullptr, QObject *parent = nullptr); + explicit RuleActionTemplate(const QString &interfaceName, const QString &actionName, int selectionId, SelectionMode selectionMode = SelectionModeAny, RuleActionParamTemplates *params = nullptr, QObject *parent = nullptr); QString interfaceName() const; - QString interfaceAction() const; + QString actionName() const; int selectionId() const; SelectionMode selectionMode() const; RuleActionParamTemplates* ruleActionParamTemplates() const; private: QString m_interfaceName; - QString m_interfaceAction; + QString m_actionName; int m_selectionId = 0; SelectionMode m_selectionMode = SelectionModeAny; RuleActionParamTemplates* m_ruleActionParamTemplates = nullptr; diff --git a/libnymea-app/ruletemplates/ruletemplates.cpp b/libnymea-app/ruletemplates/ruletemplates.cpp index 13d1bdaa..6bd94378 100644 --- a/libnymea-app/ruletemplates/ruletemplates.cpp +++ b/libnymea-app/ruletemplates/ruletemplates.cpp @@ -296,22 +296,10 @@ bool RuleTemplatesFilterModel::filterAcceptsRow(int source_row, const QModelInde // qDebug() << "Checking interface" << t->description() << t->interfaces() << "for usage with:" << m_filterInterfaceNames; - // Make sure we have a device to be used with any of the template's interfaces - if (m_filterDevicesProxy) { - foreach (const QString &toBeFound, t->interfaces()) { - bool found = false; - for (int i = 0; i < m_filterDevicesProxy->rowCount(); i++) { -// qDebug() << "Checking device:" << m_filterDevicesProxy->get(i)->deviceClass()->interfaces(); - if (m_filterDevicesProxy->get(i)->thingClass()->interfaces().contains(toBeFound)) { - found = true; - break; - } - } - if (!found) { - qDebug() << "Filtering out" << t->description() << "because required no device in the provided filter proxy implements" << toBeFound; - return false; - } - } + // Make sure we have all the things to satisfy all of the templates events/states/actions + if (m_filterDevicesProxy && !thingsSatisfyRuleTemplate(t, m_filterDevicesProxy)) { + qDebug() << "Filtering out" << t->description() << "because required no thing in the provided filter proxy satisfies definitions"; + return false; } if (!m_filterInterfaceNames.isEmpty()) { @@ -341,3 +329,107 @@ bool RuleTemplatesFilterModel::stateEvaluatorTemplateContainsInterface(StateEval } return false; } + +bool RuleTemplatesFilterModel::thingsSatisfyRuleTemplate(RuleTemplate *ruleTemplate, DevicesProxy *things) const +{ + // For improved performance it would be better to just cycle things once and flag satisfied states/events/actions + // instead of looping over all things for every entry, but for the amount of templates we have right now + // this is good enough. If needed, here's low hanging fruit to collect... + + // First check if all interfaces are around + foreach (const QString &interfaceName, ruleTemplate->interfaces()) { + bool haveThing = false; + for (int i = 0; i < things->rowCount(); i++) { + Device *thing = things->get(i); + if (thing->thingClass()->interfaces().contains(interfaceName)) { + haveThing = true; + break; + } + } + if (!haveThing) { + qDebug() << "No thing to satisfy interface" << interfaceName; + return false; + } + } + + // Given optional states/actions/events in interfaces, we also need to check for them + for (int i = 0; i < ruleTemplate->eventDescriptorTemplates()->rowCount(); i++) { + EventDescriptorTemplate *eventDescriptorTemplate = ruleTemplate->eventDescriptorTemplates()->get(i); + bool haveThing = false; + for (int j = 0; j < things->rowCount(); j++) { + Device *thing = things->get(j); + if (thing->thingClass()->eventTypes()->findByName(eventDescriptorTemplate->eventName())) { + haveThing = true; + break; + } + } + if (!haveThing) { + qDebug() << "No thing to satisfy event" << eventDescriptorTemplate->eventName(); + return false; + } + } + + if (ruleTemplate->stateEvaluatorTemplate() && !thingsSatisfyStateEvaluatorTemplate(ruleTemplate->stateEvaluatorTemplate(), things)) { + qDebug() << "No thing to satisfy state evaluator template"; + return false; + } + + for (int i = 0; i < ruleTemplate->ruleActionTemplates()->rowCount(); i++) { + RuleActionTemplate *ruleActionTemplate = ruleTemplate->ruleActionTemplates()->get(i); + bool haveThing = false; + for (int j = 0; j < things->rowCount(); j++) { + Device *thing = things->get(j); + if (thing->thingClass()->actionTypes()->findByName(ruleActionTemplate->actionName())) { + haveThing = true; + break; + } + } + if (!haveThing) { + qDebug() << "No thing to satisfy action" << ruleActionTemplate->actionName(); + return false; + } + } + + for (int i = 0; i < ruleTemplate->ruleExitActionTemplates()->rowCount(); i++) { + RuleActionTemplate *ruleExitActionTemplate = ruleTemplate->ruleExitActionTemplates()->get(i); + bool haveThing = false; + for (int j = 0; j < things->rowCount(); j++) { + Device *thing = things->get(j); + if (thing->thingClass()->actionTypes()->findByName(ruleExitActionTemplate->actionName())) { + haveThing = true; + break; + } + } + if (!haveThing) { + qDebug() << "No thing to satisfy exit action" << ruleExitActionTemplate->actionName(); + return false; + } + } + + return true; +} + +bool RuleTemplatesFilterModel::thingsSatisfyStateEvaluatorTemplate(StateEvaluatorTemplate *stateEvaluatorTemplate, DevicesProxy *things) const +{ + if (stateEvaluatorTemplate->stateDescriptorTemplate()) { + bool haveThing = false; + for (int i = 0; i < things->rowCount(); i++) { + Device *thing = things->get(i); + if (thing->thingClass()->stateTypes()->findByName(stateEvaluatorTemplate->stateDescriptorTemplate()->stateName())) { + haveThing = true; + break; + } + } + if (!haveThing) { + return false; + } + } + + for (int i = 0; i < stateEvaluatorTemplate->childEvaluatorTemplates()->rowCount(); i++) { + StateEvaluatorTemplate *childEvaluatorTemplate = stateEvaluatorTemplate->childEvaluatorTemplates()->get(i); + if (!thingsSatisfyStateEvaluatorTemplate(childEvaluatorTemplate, things)) { + return false; + } + } + return true; +} diff --git a/libnymea-app/ruletemplates/ruletemplates.h b/libnymea-app/ruletemplates/ruletemplates.h index 20c4fd19..1be08f79 100644 --- a/libnymea-app/ruletemplates/ruletemplates.h +++ b/libnymea-app/ruletemplates/ruletemplates.h @@ -38,6 +38,7 @@ class StateEvaluatorTemplate; class TimeDescriptorTemplate; class RepeatingOption; class DevicesProxy; +class Device; class RuleTemplates : public QAbstractListModel { @@ -104,6 +105,10 @@ signals: void countChanged(); +private: + bool thingsSatisfyRuleTemplate(RuleTemplate *ruleTemplate, DevicesProxy *things) const; + bool thingsSatisfyStateEvaluatorTemplate(StateEvaluatorTemplate *stateEvaluatorTemplate, DevicesProxy *things) const; + private: RuleTemplates* m_ruleTemplates = nullptr; QStringList m_filterInterfaceNames; diff --git a/libnymea-app/ruletemplates/statedescriptortemplate.cpp b/libnymea-app/ruletemplates/statedescriptortemplate.cpp index 122f612f..bbb44040 100644 --- a/libnymea-app/ruletemplates/statedescriptortemplate.cpp +++ b/libnymea-app/ruletemplates/statedescriptortemplate.cpp @@ -30,10 +30,10 @@ #include "statedescriptortemplate.h" -StateDescriptorTemplate::StateDescriptorTemplate(const QString &interfaceName, const QString &interfaceState, int selectionId, StateDescriptorTemplate::SelectionMode selectionMode, StateDescriptorTemplate::ValueOperator valueOperator, const QVariant &value, QObject *parent): +StateDescriptorTemplate::StateDescriptorTemplate(const QString &interfaceName, const QString &stateName, int selectionId, StateDescriptorTemplate::SelectionMode selectionMode, StateDescriptorTemplate::ValueOperator valueOperator, const QVariant &value, QObject *parent): QObject(parent), m_interfaceName(interfaceName), - m_interfaceState(interfaceState), + m_stateName(stateName), m_selectionId(selectionId), m_selectionMode(selectionMode), m_valueOperator(valueOperator), @@ -47,9 +47,9 @@ QString StateDescriptorTemplate::interfaceName() const return m_interfaceName; } -QString StateDescriptorTemplate::interfaceState() const +QString StateDescriptorTemplate::stateName() const { - return m_interfaceState; + return m_stateName; } int StateDescriptorTemplate::selectionId() const diff --git a/libnymea-app/ruletemplates/statedescriptortemplate.h b/libnymea-app/ruletemplates/statedescriptortemplate.h index 5ba4877c..d77e9ff3 100644 --- a/libnymea-app/ruletemplates/statedescriptortemplate.h +++ b/libnymea-app/ruletemplates/statedescriptortemplate.h @@ -38,7 +38,7 @@ class StateDescriptorTemplate : public QObject { Q_OBJECT Q_PROPERTY(QString interfaceName READ interfaceName CONSTANT) - Q_PROPERTY(QString interfaceState READ interfaceState CONSTANT) + Q_PROPERTY(QString stateName READ stateName CONSTANT) Q_PROPERTY(int selectionId READ selectionId CONSTANT) Q_PROPERTY(SelectionMode selectionMode READ selectionMode CONSTANT) Q_PROPERTY(ValueOperator valueOperator READ valueOperator CONSTANT) @@ -61,10 +61,10 @@ public: }; Q_ENUM(ValueOperator) - explicit StateDescriptorTemplate(const QString &interfaceName, const QString &interfaceState, int selectionId, SelectionMode selectionMode, ValueOperator valueOperator = ValueOperatorEquals, const QVariant &value = QVariant(), QObject *parent = nullptr); + explicit StateDescriptorTemplate(const QString &interfaceName, const QString &stateName, int selectionId, SelectionMode selectionMode, ValueOperator valueOperator = ValueOperatorEquals, const QVariant &value = QVariant(), QObject *parent = nullptr); QString interfaceName() const; - QString interfaceState() const; + QString stateName() const; int selectionId() const; SelectionMode selectionMode() const; ValueOperator valueOperator() const; @@ -72,7 +72,7 @@ public: private: QString m_interfaceName; - QString m_interfaceState; + QString m_stateName; int m_selectionId = 0; SelectionMode m_selectionMode = SelectionModeAny; ValueOperator m_valueOperator = ValueOperatorEquals; diff --git a/nymea-app/ruletemplates/mediatemplates.json b/nymea-app/ruletemplates/mediatemplates.json index bd17f1cd..aec5d644 100644 --- a/nymea-app/ruletemplates/mediatemplates.json +++ b/nymea-app/ruletemplates/mediatemplates.json @@ -63,6 +63,48 @@ ] } ] + }, + { + "description": "Automatic night mode", + "ruleNameTemplate": "Automatic night mode on %0", + "timeDescriptorTemplate": { + "calendarItemTemplates": [ + { + "startTime": "22:00", + "duration": 600, + "repeatingOption": { + "repeatingMode": "RepeatingModeDaily" + }, + "editable": true + } + ] + }, + "ruleActionTemplates": [ + { + "interfaceName": "mediacontroller", + "interfaceAction": "nightMode", + "selectionId": 0, + "params": [ + { + "name": "nightMode", + "value": true + } + ] + } + ], + "ruleExitActionTemplates": [ + { + "interfaceName": "mediacontroller", + "interfaceAction": "nightMode", + "selectionId": 0, + "params": [ + { + "name": "nightMode", + "value": false + } + ] + } + ] } ] } diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml index 20f074b2..9e55234d 100644 --- a/nymea-app/ui/Nymea.qml +++ b/nymea-app/ui/Nymea.qml @@ -454,6 +454,7 @@ ApplicationWindow { return qsTr("smart meter"); case "media": case "mediaplayer": + case "mediacontroller": //: Select ... return qsTr("media player"); case "moisturesensor": diff --git a/nymea-app/ui/magic/NewThingMagicPage.qml b/nymea-app/ui/magic/NewThingMagicPage.qml index 0315709e..e1f7e454 100644 --- a/nymea-app/ui/magic/NewThingMagicPage.qml +++ b/nymea-app/ui/magic/NewThingMagicPage.qml @@ -63,7 +63,7 @@ Page { // Fill in all EventDescriptors for (var i = rule.eventDescriptors.count; i < ruleTemplate.eventDescriptorTemplates.count; i++) { var eventDescriptorTemplate = ruleTemplate.eventDescriptorTemplates.get(i); - print("RuleFromTemplate: Filling eventDescriptor:", eventDescriptorTemplate.interfaceName, eventDescriptorTemplate.interfaceEvent, eventDescriptorTemplate.selectionId) + print("RuleFromTemplate: Filling eventDescriptor:", eventDescriptorTemplate.interfaceName, eventDescriptorTemplate.eventName, eventDescriptorTemplate.selectionId) // If we already have a thing selected for this selectionIndex, use that if (eventDescriptorTemplate.selectionId in selectedThings) { var device = engine.deviceManager.devices.getDevice(selectedThings[eventDescriptorTemplate.selectionId]); @@ -82,7 +82,7 @@ Page { // We need to pick a thing print("We need to pick a new device for selectionId", eventDescriptorTemplate.selectionId) - var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [eventDescriptorTemplate.interfaceName]}); + var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [eventDescriptorTemplate.interfaceName], requiredEventName: eventDescriptorTemplate.eventName}); page.thingSelected.connect(function(device) { selectedThings[eventDescriptorTemplate.selectionId] = device.id; selectedThingNames[eventDescriptorTemplate.selectionId] = device.name; @@ -152,13 +152,13 @@ Page { for (var i = rule.actions.count; i < ruleTemplate.ruleActionTemplates.count; i++) { var ruleActionTemplate = ruleTemplate.ruleActionTemplates.get(i); - print("RuleFromTemplate: Filling ruleAction:", ruleActionTemplate.interfaceName, ruleActionTemplate.interfaceAction, ruleActionTemplate.selectionId) + print("RuleFromTemplate: Filling ruleAction:", ruleActionTemplate.interfaceName, ruleActionTemplate.actionName, ruleActionTemplate.selectionId) if (ruleActionTemplate.selectionMode === RuleActionTemplate.SelectionModeInterface) { // TODO: Implement blacklist for interface based actions var ruleAction = rule.actions.createNewRuleAction(); ruleAction.interfaceName = ruleActionTemplate.interfaceName; - ruleAction.interfaceAction = ruleActionTemplate.interfaceAction; + ruleAction.interfaceAction = ruleActionTemplate.actionName; for (var j = 0; j < ruleActionTemplate.ruleActionParamTemplates.count; j++) { var ruleActionParam = ruleActionTemplate.ruleActionParamTemplates.get(j) ruleAction.ruleActionParams.setRuleActionParamByName(ruleActionParam.paramName, ruleActionParam.value) @@ -188,7 +188,7 @@ Page { // Ok, we need to pick a thing var multipleSelection = ruleActionTemplate.selectionMode === RuleActionTemplate.SelectionModeDevices; - var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [ruleActionTemplate.interfaceName], multipleSelection: multipleSelection}); + var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [ruleActionTemplate.interfaceName], requiredActionName: ruleActionTemplate.actionName, multipleSelection: multipleSelection}); page.thingSelected.connect(function(device) { selectedThings[ruleActionTemplate.selectionId] = device.id; selectedThingNames[ruleActionTemplate.selectionId] = device.name; @@ -216,7 +216,7 @@ Page { // TODO: Implement blacklist for interface based actions var ruleExitAction = rule.exitActions.createNewRuleAction(); ruleExitAction.interfaceName = ruleExitActionTemplate.interfaceName; - ruleExitAction.interfaceAction = ruleExitActionTemplate.interfaceAction; + ruleExitAction.interfaceAction = ruleExitActionTemplate.actionName; for (var j = 0; j < ruleExitActionTemplate.ruleActionParamTemplates.count; j++) { var ruleActionParam = ruleExitActionTemplate.ruleActionParamTemplates.get(j) ruleExitAction.ruleActionParams.setRuleActionParam(ruleActionParam.paramName, ruleActionParam.value) @@ -244,7 +244,7 @@ Page { // Ok, we need to pick a thing var multipleSelection = ruleActionTemplate.selectionMode === RuleActionTemplate.SelectionModeDevices; - var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [ruleExitActionTemplate.interfaceName], multipleSelection: multipleSelection}); + var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [ruleExitActionTemplate.interfaceName], requiredActionName: ruleExitActionTemplate.actionName, multipleSelection: multipleSelection}); page.thingSelected.connect(function(device) { selectedThings[ruleExitActionTemplate.selectionId] = device.id; selectedThingNames[ruleExitActionTemplate.selectionId] = device.name; @@ -309,7 +309,7 @@ Page { print("filling in state evaluator for selection mode:", stateEvaluatorTemplate.stateDescriptorTemplate.selectionMode) if (stateEvaluatorTemplate.stateDescriptorTemplate.selectionMode === StateDescriptor.SelectionModeInterface) { stateEvaluator.stateDescriptor.interfaceName = stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName; - stateEvaluator.stateDescriptor.interfaceState = stateEvaluatorTemplate.stateDescriptorTemplate.interfaceState; + stateEvaluator.stateDescriptor.interfaceState = stateEvaluatorTemplate.stateDescriptorTemplate.stateName; stateEvaluator.stateDescriptor.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; selectedInterfaces[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] = stateEvaluator.stateDescriptor.interfaceName; @@ -323,7 +323,7 @@ Page { var device = engine.deviceManager.devices.getDevice(deviceId) var deviceClass = engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); stateEvaluator.stateDescriptor.deviceId = deviceId; - stateEvaluator.stateDescriptor.stateTypeId = deviceClass.stateTypes.findByName(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceState).id + stateEvaluator.stateDescriptor.stateTypeId = deviceClass.stateTypes.findByName(stateEvaluatorTemplate.stateDescriptorTemplate.stateName).id stateEvaluator.stateDescriptor.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; fillRuleFromTemplate(rule, ruleTemplate); @@ -331,7 +331,7 @@ Page { } if (root.device && !deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName) >= 0) { stateEvaluator.stateDescriptor.deviceId = root.device.id; - stateEvaluator.stateDescriptor.stateTypeId = root.deviceClass.stateTypes.findByName(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceState).id + stateEvaluator.stateDescriptor.stateTypeId = root.deviceClass.stateTypes.findByName(stateEvaluatorTemplate.stateDescriptorTemplate.stateName).id stateEvaluator.stateDescriptor.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; selectedThings[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] = root.device.id; @@ -341,11 +341,11 @@ Page { } print("opening SelectThingPage for shownInterfaces:") print("..", stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName) - var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName], allowSelectAny: stateEvaluatorTemplate.stateDescriptorTemplate.selectionMode === StateDescriptorTemplate.SelectionModeAny}); + var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName], requiredStateName: stateEvaluatorTemplate.stateDescriptorTemplate.stateName, allowSelectAny: stateEvaluatorTemplate.stateDescriptorTemplate.selectionMode === StateDescriptorTemplate.SelectionModeAny}); page.thingSelected.connect(function(device) { var deviceClass = engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); stateEvaluator.stateDescriptor.deviceId = device.id; - stateEvaluator.stateDescriptor.stateTypeId = deviceClass.stateTypes.findByName(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceState).id; + stateEvaluator.stateDescriptor.stateTypeId = deviceClass.stateTypes.findByName(stateEvaluatorTemplate.stateDescriptorTemplate.stateName).id; stateEvaluator.stateDescriptor.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; selectedThings[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] = device.id; @@ -354,7 +354,7 @@ Page { }) page.onAnySelected.connect(function() { stateEvaluator.stateDescriptor.interfaceName = stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName; - stateEvaluator.stateDescriptor.interfaceState = stateEvaluatorTemplate.stateDescriptorTemplate.interfaceState; + stateEvaluator.stateDescriptor.interfaceState = stateEvaluatorTemplate.stateDescriptorTemplate.stateName; stateEvaluator.stateDescriptor.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; selectedInterfaces[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] = stateEvaluator.stateDescriptor.interfaceName; @@ -381,7 +381,7 @@ Page { var eventDescriptor = rule.eventDescriptors.createNewEventDescriptor(); eventDescriptor.deviceId = device.id; var deviceClass = engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); - eventDescriptor.eventTypeId = deviceClass.eventTypes.findByName(eventDescriptorTemplate.interfaceEvent).id + eventDescriptor.eventTypeId = deviceClass.eventTypes.findByName(eventDescriptorTemplate.eventName).id var needsParams = false; var eventType = deviceClass.eventTypes.getEventType(eventDescriptor.eventTypeId); @@ -423,9 +423,9 @@ Page { var ruleAction = ruleActions.createNewRuleAction(); var deviceClass = engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); - ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleActionTemplate.interfaceAction).id + ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleActionTemplate.actionName).id ruleAction.deviceId = device.id; - print("Creating action", ruleActionTemplate.interfaceAction, "on device class", deviceClass.displayName) + print("Creating action", ruleActionTemplate.actionName, "on device class", deviceClass.displayName) var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId); @@ -441,7 +441,7 @@ Page { for (var k = 0; k < ruleTemplate.eventDescriptorTemplates.count; k++) { var tmp = ruleTemplate.eventDescriptorTemplates.get(k); print("evaluating eventDescriptor", tmp.interfaceName) - if (tmp.interfaceName === ruleActionParamTemplate.eventInterface && tmp.interfaceEvent === ruleActionParamTemplate.eventName) { + if (tmp.interfaceName === ruleActionParamTemplate.eventInterface && tmp.eventName === ruleActionParamTemplate.eventName) { eventDescriptorTemplate = tmp; break; } diff --git a/nymea-app/ui/magic/SelectThingPage.qml b/nymea-app/ui/magic/SelectThingPage.qml index 0c3fbe37..512a14dd 100644 --- a/nymea-app/ui/magic/SelectThingPage.qml +++ b/nymea-app/ui/magic/SelectThingPage.qml @@ -45,6 +45,9 @@ Page { property alias shownInterfaces: devicesProxy.shownInterfaces property bool allowSelectAny: false property bool multipleSelection: false + property alias requiredEventName: devicesProxy.requiredEventName + property alias requiredStateName: devicesProxy.requiredStateName + property alias requiredActionName: devicesProxy.requiredActionName signal backPressed(); signal thingSelected(var device);