From ea3e2d210695e6de5d00b86c956dfd0f289f28c2 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 7 Jan 2019 23:28:55 +0100 Subject: [PATCH 1/2] Add rule templates for daylight and presence sensors --- libnymea-app-core/devicemanager.cpp | 2 +- libnymea-app-core/rulemanager.cpp | 2 +- .../ruletemplates/ruletemplates.cpp | 10 +- libnymea-common/types/interfaces.cpp | 5 + nymea-app/nymea-app.pro | 4 +- nymea-app/ruletemplates.qrc | 2 + nymea-app/ruletemplates/daylightsensor.json | 110 +++++++++++ .../presencesensortemplates.json | 175 ++++++++++++++++++ nymea-app/ui/Nymea.qml | 2 + .../devicepages/SensorDevicePagePost110.qml | 1 - .../ui/magic/EventDescriptorDelegate.qml | 18 +- nymea-app/ui/magic/NewThingMagicPage.qml | 3 +- 12 files changed, 320 insertions(+), 14 deletions(-) create mode 100644 nymea-app/ruletemplates/daylightsensor.json create mode 100644 nymea-app/ruletemplates/presencesensortemplates.json diff --git a/libnymea-app-core/devicemanager.cpp b/libnymea-app-core/devicemanager.cpp index 7cd02d87..d647a182 100644 --- a/libnymea-app-core/devicemanager.cpp +++ b/libnymea-app-core/devicemanager.cpp @@ -241,7 +241,7 @@ void DeviceManager::getConfiguredDevicesResponse(const QVariantMap ¶ms) device->setStateValue(stateTypeId, value); // qDebug() << "Set device state value:" << device->stateValue(stateTypeId) << value; } - qDebug() << "Confgured 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; } diff --git a/libnymea-app-core/rulemanager.cpp b/libnymea-app-core/rulemanager.cpp index 563f514f..daa7b192 100644 --- a/libnymea-app-core/rulemanager.cpp +++ b/libnymea-app-core/rulemanager.cpp @@ -168,7 +168,7 @@ void RuleManager::getRuleDetailsReply(const QVariantMap ¶ms) void RuleManager::onAddRuleReply(const QVariantMap ¶ms) { - qDebug() << "Add rule reply:" << params.value("params").toMap().value("ruleError").toString(); + qDebug() << "Add rule reply:" << params;//.value("params").toMap().value("ruleError").toString(); emit addRuleReply(params.value("params").toMap().value("ruleError").toString(), params.value("params").toMap().value("ruleId").toString()); } diff --git a/libnymea-app-core/ruletemplates/ruletemplates.cpp b/libnymea-app-core/ruletemplates/ruletemplates.cpp index 41e2d549..f543aaed 100644 --- a/libnymea-app-core/ruletemplates/ruletemplates.cpp +++ b/libnymea-app-core/ruletemplates/ruletemplates.cpp @@ -62,6 +62,12 @@ RuleTemplates::RuleTemplates(QObject *parent) : QAbstractListModel(parent) evpt->setParamName(eventDescriptorParamTemplate.value("name").toString()); if (eventDescriptorParamTemplate.contains("value")) { evpt->setValue(eventDescriptorParamTemplate.value("value")); + if (!eventDescriptorParamTemplate.contains("operator")) { + qWarning() << "BROKEN Template: Operator missing for event descriptor template" << qUtf8Printable(QJsonDocument::fromVariant(eventDescriptorParamTemplate).toJson(QJsonDocument::Indented)); + } else { + QMetaEnum operatorEnum = QMetaEnum::fromType(); + evpt->setOperatorType(static_cast(operatorEnum.keyToValue(eventDescriptorParamTemplate.value("operator").toByteArray().data()))); + } } evt->paramDescriptors()->addParamDescriptor(evpt); } @@ -144,9 +150,9 @@ RuleTemplates::RuleTemplates(QObject *parent) : QAbstractListModel(parent) t->ruleExitActionTemplates()->addRuleActionTemplate(rat); } - qDebug() << "Added rule template:" << t->ruleActionTemplates()->rowCount(); m_list.append(t); } +// qDebug() << "Loaded" << m_list.count() << "rule templates"; } } @@ -187,7 +193,7 @@ bool RuleTemplatesFilterModel::filterAcceptsRow(int source_row, const QModelInde return false; } RuleTemplate *t = m_ruleTemplates->get(source_row); - qDebug() << "Checking interface" << t->description() << t->interfaceName() << "for usage with:" << m_filterInterfaceNames; +// qDebug() << "Checking interface" << t->description() << t->interfaceName() << "for usage with:" << m_filterInterfaceNames; if (!m_filterInterfaceNames.isEmpty()) { if (!m_filterInterfaceNames.contains(t->interfaceName())) { return false; diff --git a/libnymea-common/types/interfaces.cpp b/libnymea-common/types/interfaces.cpp index 3546c4de..9916fc0c 100644 --- a/libnymea-common/types/interfaces.cpp +++ b/libnymea-common/types/interfaces.cpp @@ -27,6 +27,11 @@ Interfaces::Interfaces(QObject *parent) : QAbstractListModel(parent) addParamType(pts, "body", tr("Message body"), QVariant::String); addActionType("notifications", "notify", tr("Send notification"), pts); + addInterface("power", tr("Powered things")); + addStateType("power", "power", QVariant::Bool, true, + tr("Thing is turned on"), + tr("A thing is turned on or off"), + tr("Turn things on or off")); addInterface("light", tr("Lights")); addStateType("light", "power", QVariant::Bool, true, diff --git a/nymea-app/nymea-app.pro b/nymea-app/nymea-app.pro index a2b96c44..da237c2c 100644 --- a/nymea-app/nymea-app.pro +++ b/nymea-app/nymea-app.pro @@ -126,5 +126,7 @@ target.path = /usr/bin INSTALLS += target DISTFILES += \ - ruletemplates/smartmetertemplates.json + ruletemplates/smartmetertemplates.json \ + ruletemplates/presencesensortemplates.json \ + ruletemplates/daylightsensor.json diff --git a/nymea-app/ruletemplates.qrc b/nymea-app/ruletemplates.qrc index 24df3a96..579d5223 100644 --- a/nymea-app/ruletemplates.qrc +++ b/nymea-app/ruletemplates.qrc @@ -4,5 +4,7 @@ ruletemplates/notificationtemplates.json ruletemplates/accesscontroltemplates.json ruletemplates/smartmetertemplates.json + ruletemplates/presencesensortemplates.json + ruletemplates/daylightsensor.json diff --git a/nymea-app/ruletemplates/daylightsensor.json b/nymea-app/ruletemplates/daylightsensor.json new file mode 100644 index 00000000..4d1f251d --- /dev/null +++ b/nymea-app/ruletemplates/daylightsensor.json @@ -0,0 +1,110 @@ +{ + "templates": [ + { + "interfaceName": "daylightsensor", + "description": "Turn on a light while it's dark outside.", + "ruleNameTemplate": "Turn on %1 while it's dark outside", + "stateEvaluatorTemplate": { + "stateDescriptorTemplate": { + "interfaceName": "daylightsensor", + "interfaceState": "daylight", + "selectionId": 0, + "operator": "ValueOperatorEquals", + "value": false + } + }, + "ruleActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "true" + } + ] + } + ], + "ruleExitActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "false" + } + ] + } + ] + }, + { + "interfaceName": "daylightsensor", + "description": "Turn on a light when it gets dark outside.", + "ruleNameTemplate": "Turn on %1 it gets dark outside (%0).", + "eventDescriptorTemplates": [ + { + "interfaceName": "daylightsensor", + "interfaceEvent": "daylight", + "selectionId": 0, + "params": [ + { + "name": "daylight", + "value": false, + "operator": "ValueOperatorEquals" + } + ] + } + ], + "ruleActionTemplates": [ + { + "interfaceName": "light", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "true" + } + ] + } + ] + }, + { + "interfaceName": "daylightsensor", + "description": "Turn on all lights when it gets dark outside.", + "ruleNameTemplate": "Turn on all lights when it gets dark outside.", + "eventDescriptorTemplates": [ + { + "interfaceName": "daylightsensor", + "interfaceEvent": "daylight", + "selectionId": 0, + "params": [ + { + "name": "daylight", + "value": false, + "operator": "ValueOperatorEquals" + } + ] + } + ], + "ruleActionTemplates": [ + { + "interfaceName": "light", + "interfaceAction": "power", + "selectionId": 1, + "selectionMode": "SelectionModeInterface", + "params": [ + { + "name": "power", + "value": "true" + } + ] + } + ] + } + ] +} + diff --git a/nymea-app/ruletemplates/presencesensortemplates.json b/nymea-app/ruletemplates/presencesensortemplates.json new file mode 100644 index 00000000..14cccfd3 --- /dev/null +++ b/nymea-app/ruletemplates/presencesensortemplates.json @@ -0,0 +1,175 @@ +{ + "templates": [ + { + "interfaceName": "presencesensor", + "description": "Turn on something while this device is present...", + "ruleNameTemplate": "Turn on %1 while %0 is present", + "stateEvaluatorTemplate": { + "stateDescriptorTemplate": { + "interfaceName": "presencesensor", + "interfaceState": "isPresent", + "selectionId": 0, + "operator": "ValueOperatorEquals", + "value": true + } + }, + "ruleActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "true" + } + ] + } + ], + "ruleExitActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "false" + } + ] + } + ] + }, + { + "interfaceName": "presencesensor", + "description": "Turn off something when this device leaves...", + "ruleNameTemplate": "Turn off %1 when %0 leaves", + "eventDescriptorTemplates": [ + { + "interfaceName": "presencesensor", + "interfaceEvent": "isPresent", + "selectionId": 0, + "params": [ + { + "name": "isPresent", + "value": false, + "operator": "ValueOperatorEquals" + } + ] + } + ], + "ruleActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "false" + } + ] + } + ] + }, + { + "interfaceName": "presencesensor", + "description": "Turn off everything when this device leaves...", + "ruleNameTemplate": "Turn off everything when %0 leaves", + "eventDescriptorTemplates": [ + { + "interfaceName": "presencesensor", + "interfaceEvent": "isPresent", + "selectionId": 0, + "params": [ + { + "name": "isPresent", + "value": false, + "operator": "ValueOperatorEquals" + } + ] + } + ], + "ruleActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "selectionMode": "SelectionModeInterface", + "params": [ + { + "name": "power", + "value": "false" + } + ] + } + ] + }, + { + "interfaceName": "presencesensor", + "description": "Turn off all lights when this device leaves...", + "ruleNameTemplate": "Turn off all lights when %0 leaves", + "eventDescriptorTemplates": [ + { + "interfaceName": "presencesensor", + "interfaceEvent": "isPresent", + "selectionId": 0, + "params": [ + { + "name": "isPresent", + "value": false, + "operator": "ValueOperatorEquals" + } + ] + } + ], + "ruleActionTemplates": [ + { + "interfaceName": "light", + "interfaceAction": "power", + "selectionId": 1, + "selectionMode": "SelectionModeInterface", + "params": [ + { + "name": "power", + "value": "false" + } + ] + } + ] + }, + { + "interfaceName": "presencesensor", + "description": "Turn on something when this device arrives...", + "ruleNameTemplate": "Turn on %1 when %0 arrives", + "eventDescriptorTemplates": [ + { + "interfaceName": "presencesensor", + "interfaceEvent": "isPresent", + "selectionId": 0, + "params": [ + { + "name": "isPresent", + "value": true, + "operator": "ValueOperatorEquals" + } + ] + } + ], + "ruleActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "true" + } + ] + } + ] + } + ] +} + diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml index 2239f8e1..32df5cac 100644 --- a/nymea-app/ui/Nymea.qml +++ b/nymea-app/ui/Nymea.qml @@ -253,6 +253,8 @@ ApplicationWindow { return qsTr("battery powered thing") case "connectable": return qsTr("connectable thing") + case "power": + return qsTr("switchable thing") default: console.warn("Unhandled interfaceToDisplayName:", name) } diff --git a/nymea-app/ui/devicepages/SensorDevicePagePost110.qml b/nymea-app/ui/devicepages/SensorDevicePagePost110.qml index 9044d34f..b70b737b 100644 --- a/nymea-app/ui/devicepages/SensorDevicePagePost110.qml +++ b/nymea-app/ui/devicepages/SensorDevicePagePost110.qml @@ -13,7 +13,6 @@ ListView { Component.onCompleted: { var supportedInterfaces = ["temperaturesensor", "humiditysensor", "pressuresensor", "moisturesensor", "lightsensor", "conductivitysensor", "noisesensor", "co2sensor", "presencesensor", "daylightsensor"] for (var i = 0; i < supportedInterfaces.length; i++) { - print("checking", root.deviceClass.name, root.deviceClass.interfaces) if (root.deviceClass.interfaces.indexOf(supportedInterfaces[i]) >= 0) { append({name: supportedInterfaces[i]}); } diff --git a/nymea-app/ui/magic/EventDescriptorDelegate.qml b/nymea-app/ui/magic/EventDescriptorDelegate.qml index bfc30b1b..63ba021a 100644 --- a/nymea-app/ui/magic/EventDescriptorDelegate.qml +++ b/nymea-app/ui/magic/EventDescriptorDelegate.qml @@ -10,11 +10,11 @@ MeaListItemDelegate { canDelete: true progressive: false - property var eventDescriptor: null - readonly property var device: eventDescriptor ? engine.deviceManager.devices.getDevice(eventDescriptor.deviceId) : null - readonly property var deviceClass: device ? engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null - readonly property var iface: eventDescriptor.interfaceName ? Interfaces.findByName(eventDescriptor.interfaceName) : null - readonly property var eventType: deviceClass ? deviceClass.eventTypes.getEventType(eventDescriptor.eventTypeId) + property EventDescriptor eventDescriptor: null + readonly property Device device: eventDescriptor ? engine.deviceManager.devices.getDevice(eventDescriptor.deviceId) : null + readonly property DeviceClass deviceClass: device ? engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null + readonly property Interface iface: eventDescriptor.interfaceName ? Interfaces.findByName(eventDescriptor.interfaceName) : null + readonly property EventType eventType: deviceClass ? deviceClass.eventTypes.getEventType(eventDescriptor.eventTypeId) : iface ? iface.eventTypes.findByName(eventDescriptor.interfaceEvent) : null signal removeEventDescriptor() @@ -51,16 +51,20 @@ MeaListItemDelegate { operatorString = " ? "; } + var paramType = paramDescriptor.paramTypeId + ? root.eventType.paramTypes.getParamType(paramDescriptor.paramTypeId) + : root.eventType.paramTypes.findByName(paramDescriptor.paramName) + if (i === 0) { // TRANSLATORS: example: "only if temperature > 5" ret = qsTr("only if %1 %2 %3") - .arg(root.eventType.paramTypes.getParamType(paramDescriptor.paramTypeId).displayName) + .arg(paramType.displayName) .arg(operatorString) .arg(paramDescriptor.value) } else { // TRANSLATORS: example: "and temperature > 5" ret += " " + qsTr("and %1 %2 %3") - .arg(root.eventType.paramTypes.getParamType(paramDescriptor.paramTypeId).displayName) + .arg(paramType.displayName) .arg(operatorString) .arg(model.value) } diff --git a/nymea-app/ui/magic/NewThingMagicPage.qml b/nymea-app/ui/magic/NewThingMagicPage.qml index ae0caa08..95b584b4 100644 --- a/nymea-app/ui/magic/NewThingMagicPage.qml +++ b/nymea-app/ui/magic/NewThingMagicPage.qml @@ -257,7 +257,8 @@ Page { for (var j = 0; j < eventDescriptorTemplate.paramDescriptors.count; j++) { var paramDescriptorTemplate = eventDescriptorTemplate.paramDescriptors.get(j); if (paramDescriptorTemplate.value !== undefined) { - eventDescriptor.paramDescriptors.addParamDescriptor(paramDescriptorTemplate.paramName, paramDescriptorTemplate.value); + print("Adding operator:", paramDescriptorTemplate.operatorType) + eventDescriptor.paramDescriptors.setParamDescriptorByName(paramDescriptorTemplate.paramName, paramDescriptorTemplate.value, paramDescriptorTemplate.operatorType); } else { needsParams = true; } From d274b1b61a739b55a6dfa438db4efbed098829aa Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 8 Jan 2019 01:12:39 +0100 Subject: [PATCH 2/2] add some more templates and fix issues in the template generation code --- nymea-app/nymea-app.pro | 3 +- nymea-app/ruletemplates.qrc | 1 + nymea-app/ruletemplates/lighttemplates.json | 85 +++ nymea-app/ui/Nymea.qml | 4 + nymea-app/ui/magic/NewThingMagicPage.qml | 596 ++++++++++---------- nymea-app/ui/magic/SelectThingPage.qml | 9 +- 6 files changed, 409 insertions(+), 289 deletions(-) create mode 100644 nymea-app/ruletemplates/lighttemplates.json diff --git a/nymea-app/nymea-app.pro b/nymea-app/nymea-app.pro index da237c2c..3b750ec6 100644 --- a/nymea-app/nymea-app.pro +++ b/nymea-app/nymea-app.pro @@ -128,5 +128,6 @@ INSTALLS += target DISTFILES += \ ruletemplates/smartmetertemplates.json \ ruletemplates/presencesensortemplates.json \ - ruletemplates/daylightsensor.json + ruletemplates/daylightsensor.json \ + ruletemplates/lighttemplates.json diff --git a/nymea-app/ruletemplates.qrc b/nymea-app/ruletemplates.qrc index 579d5223..e5c6de98 100644 --- a/nymea-app/ruletemplates.qrc +++ b/nymea-app/ruletemplates.qrc @@ -6,5 +6,6 @@ ruletemplates/smartmetertemplates.json ruletemplates/presencesensortemplates.json ruletemplates/daylightsensor.json + ruletemplates/lighttemplates.json diff --git a/nymea-app/ruletemplates/lighttemplates.json b/nymea-app/ruletemplates/lighttemplates.json new file mode 100644 index 00000000..633aeb52 --- /dev/null +++ b/nymea-app/ruletemplates/lighttemplates.json @@ -0,0 +1,85 @@ +{ + "templates": [ + { + "interfaceName": "power", + "description": "Turn on while its dark outside.", + "ruleNameTemplate": "Turn on %1 while it's dark outside", + "stateEvaluatorTemplate": { + "stateDescriptorTemplate": { + "interfaceName": "daylightsensor", + "interfaceState": "daylight", + "selectionId": 0, + "operator": "ValueOperatorEquals", + "value": false + } + }, + "ruleActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "true" + } + ] + } + ], + "ruleExitActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "false" + } + ] + } + ] + }, + { + "interfaceName": "power", + "description": "Turn on while someone is around.", + "ruleNameTemplate": "Turn on %1 while %0 is present", + "stateEvaluatorTemplate": { + "stateDescriptorTemplate": { + "interfaceName": "presencesensor", + "interfaceState": "isPresent", + "selectionId": 0, + "operator": "ValueOperatorEquals", + "value": true + } + }, + "ruleActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "true" + } + ] + } + ], + "ruleExitActionTemplates": [ + { + "interfaceName": "power", + "interfaceAction": "power", + "selectionId": 1, + "params": [ + { + "name": "power", + "value": "false" + } + ] + } + ] + } + ] +} + diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml index 32df5cac..f845cd70 100644 --- a/nymea-app/ui/Nymea.qml +++ b/nymea-app/ui/Nymea.qml @@ -255,6 +255,10 @@ ApplicationWindow { return qsTr("connectable thing") case "power": return qsTr("switchable thing") + case "daylightsensor": + return qsTr("daylight sensor") + case "presencesensor": + return qsTr("presence sensor") default: console.warn("Unhandled interfaceToDisplayName:", name) } diff --git a/nymea-app/ui/magic/NewThingMagicPage.qml b/nymea-app/ui/magic/NewThingMagicPage.qml index 95b584b4..fc8e4390 100644 --- a/nymea-app/ui/magic/NewThingMagicPage.qml +++ b/nymea-app/ui/magic/NewThingMagicPage.qml @@ -14,312 +14,341 @@ Page { signal done(); signal manualCreation(); - function fillRuleFromTemplate(rule, ruleTemplate, selectedThings) { - if (selectedThings === undefined) { - selectedThings = []; - } + function createRuleFromTemplate(ruleTemplate) { + d.selectedThings = {} + d.selectedInterfaces = {} + var rule = engine.ruleManager.createNewRule(); + d.fillRuleFromTemplate(rule, ruleTemplate); + } - // 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) - // If we already have a thing selected for this selectionIndex, use that - if (selectedThings.length > eventDescriptorTemplate.selectionId) { - var device = engine.deviceManager.devices.getDevice(selectedThings[eventDescriptorTemplate.selectionId]); - createEventDescriptor(rule, ruleTemplate, selectedThings, device, eventDescriptorTemplate) - return; - } - // Ok, we didn't pick a thing for this selectionId before. Did we already use the one we opened this page from? - if (selectedThings.indexOf(root.device.id) === -1 && root.deviceClass.interfaces.indexOf(eventDescriptorTemplate.interfaceName) >= 0 && eventDescriptorTemplate.interfaceName === ruleTemplate.interfaceName) { - selectedThings.push(root.device.id); - createEventDescriptor(rule, ruleTemplate, selectedThings, root.device, eventDescriptorTemplate) - return; - } + QtObject { + id: d + property var selectedThings: ({}) + property var selectedInterfaces: ({}) - // We need to pick a thing - var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [eventDescriptorTemplate.interfaceName]}); - page.thingSelected.connect(function(device) { - selectedThings.push(device.id); - createEventDescriptor(rule, ruleTemplate, selectedThings, device, eventDescriptorTemplate) - return; - }) - page.backPressed.connect(function() {rule.destroy(); root.done();}) - return; - } + function fillRuleFromTemplate(rule, ruleTemplate) { + print("Filling rule") - // Fill in StateEvaluator - if (ruleTemplate.stateEvaluatorTemplate !== null) { - if (rule.stateEvaluator === null) { - var stateEvaluator = rule.createStateEvaluator(); - rule.setStateEvaluator(stateEvaluator); - fillStateEvaluatorFromTemplate(rule, ruleTemplate, stateEvaluator, ruleTemplate.stateEvaluatorTemplate, selectedThings); - return; - } - var more = fillStateEvaluatorFromTemplate(rule, ruleTemplate, rule.stateEvaluator, ruleTemplate.stateEvaluatorTemplate, selectedThings); - if (more) { - return; - } - } - - for (var i = rule.actions.count; i < ruleTemplate.ruleActionTemplates.count; i++) { - var ruleActionTemplate = ruleTemplate.ruleActionTemplates.get(i); - - 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; - for (var j = 0; j < ruleActionTemplate.ruleActionParamTemplates.count; j++) { - var ruleActionParam = ruleActionTemplate.ruleActionParamTemplates.get(j) - ruleAction.ruleActionParams.setRuleActionParamByName(ruleActionParam.paramName, ruleActionParam.value) + // 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) + // 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]); + createEventDescriptor(rule, ruleTemplate, device, eventDescriptorTemplate) + return; } - rule.actions.addRuleAction(ruleAction); - fillRuleFromTemplate(rule, ruleTemplate, selectedThings); - return; - } - - // Did we pick a thing for this index before? - if (selectedThings.length > ruleActionTemplate.selectionId) { - var device = engine.deviceManager.devices.getDevice(selectedThings[ruleActionTemplate.selectionId]); - createRuleAction(rule, ruleTemplate, selectedThings, rule.actions, device, ruleActionTemplate) - return; - } - - // Did we already use the thing we opened this page from? - if (selectedThings.indexOf(root.device.id) === -1 && root.deviceClass.interfaces.indexOf(ruleActionTemplate.interfaceName) >= 0 && ruleActionTemplate.interfaceName === ruleTemplate.interfaceName) { - selectedThings.push(root.device.id); - createRuleAction(rule, ruleTemplate, selectedThings, rule.actions, root.device, ruleActionTemplate) - return; - } - - // Ok, we need to pick a thing - print("Need to select a thing") - var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [ruleActionTemplate.interfaceName]}); - page.thingSelected.connect(function(device) { - selectedThings.push(device.id); - createRuleAction(rule, ruleTemplate, selectedThings, rule.actions, device, ruleActionTemplate) - return; - }) - page.backPressed.connect(function() {rule.destroy(); root.done();}) - return; - } - - - for (var i = rule.exitActions.count; i < ruleTemplate.ruleExitActionTemplates.count; i++) { - var ruleExitActionTemplate = ruleTemplate.ruleExitActionTemplates.get(i); - - if (ruleExitActionTemplate.selectionMode === RuleActionTemplate.SelectionModeInterface) { - // TODO: Implement blacklist for interface based actions - var ruleExitAction = rule.exitActions.createNewRuleAction(); - ruleExitAction.interfaceName = ruleExitActionTemplate.interfaceName; - ruleExitAction.interfaceAction = ruleExitActionTemplate.interfaceAction; - for (var j = 0; j < ruleExitActionTemplate.ruleActionParamTemplates.count; j++) { - var ruleActionParam = ruleExitActionTemplate.ruleActionParamTemplates.get(j) - ruleExitAction.ruleActionParams.setRuleActionParam(ruleActionParam.paramName, ruleActionParam.value) + // Ok, we didn't pick a thing for this selectionId before. Did we already use the one we opened this page from? + if (!deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(eventDescriptorTemplate.interfaceName) >= 0 && eventDescriptorTemplate.interfaceName === ruleTemplate.interfaceName) { + selectedThings[eventDescriptorTemplate.selectionId] = root.device.id; + createEventDescriptor(rule, ruleTemplate, root.device, eventDescriptorTemplate) + return; } - rule.exitActions.addRuleAction(ruleAction); - fillRuleFromTemplate(rule, ruleTemplate, selectedThings); + + // We need to pick a thing + var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [eventDescriptorTemplate.interfaceName]}); + page.thingSelected.connect(function(device) { + selectedThings[eventDescriptorTemplate.selectionId] = device.id; + createEventDescriptor(rule, ruleTemplate, device, eventDescriptorTemplate) + return; + }) + page.backPressed.connect(function() {rule.destroy(); root.done();}) return; } - // Did we pick a thing for this index before? - if (selectedThings.length > ruleExitActionTemplate.selectionId) { - var device = engine.deviceManager.devices.getDevice(selectedThings[ruleExitActionTemplate.selectionId]); - createRuleAction(rule, ruleTemplate, selectedThings, rule.exitActions, device, ruleExitActionTemplate); + // Fill in StateEvaluator + if (ruleTemplate.stateEvaluatorTemplate !== null) { + if (rule.stateEvaluator === null) { + var stateEvaluator = rule.createStateEvaluator(); + rule.setStateEvaluator(stateEvaluator); + fillStateEvaluatorFromTemplate(rule, ruleTemplate, stateEvaluator, ruleTemplate.stateEvaluatorTemplate); + return; + } + var more = fillStateEvaluatorFromTemplate(rule, ruleTemplate, rule.stateEvaluator, ruleTemplate.stateEvaluatorTemplate); + if (more) { + return; + } + } + + for (var i = rule.actions.count; i < ruleTemplate.ruleActionTemplates.count; i++) { + var ruleActionTemplate = ruleTemplate.ruleActionTemplates.get(i); + + 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; + for (var j = 0; j < ruleActionTemplate.ruleActionParamTemplates.count; j++) { + var ruleActionParam = ruleActionTemplate.ruleActionParamTemplates.get(j) + ruleAction.ruleActionParams.setRuleActionParamByName(ruleActionParam.paramName, ruleActionParam.value) + } + selectedInterfaces[ruleActionTemplate.selectionId] = ruleAction.interfaceName; + rule.actions.addRuleAction(ruleAction); + fillRuleFromTemplate(rule, ruleTemplate); + return; + } + + // Did we pick a thing for this index before? + if (ruleActionTemplate.selectionId in selectedThings) { + var device = engine.deviceManager.devices.getDevice(selectedThings[ruleActionTemplate.selectionId]); + createRuleAction(rule, ruleTemplate, rule.actions, device, ruleActionTemplate) + return; + } + + // Did we already use the thing we opened this page from? + if (!deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(ruleActionTemplate.interfaceName) >= 0 && ruleActionTemplate.interfaceName === ruleTemplate.interfaceName) { + selectedThings[ruleActionTemplate.selectionId] = root.device.id; + createRuleAction(rule, ruleTemplate, rule.actions, root.device, ruleActionTemplate) + return; + } + + // Ok, we need to pick a thing + print("Need to select a thing") + var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [ruleActionTemplate.interfaceName]}); + page.thingSelected.connect(function(device) { + selectedThings[ruleActionTemplate.selectionId] = device.id; + createRuleAction(rule, ruleTemplate, rule.actions, device, ruleActionTemplate) + return; + }) + page.backPressed.connect(function() {rule.destroy(); root.done();}) return; } - // Did we already use the thing we opened this page from? - if (selectedThings.indexOf(root.device.id) === -1 && root.deviceClass.interfaces.indexOf(ruleExitActionTemplate.interfaceName) >= 0 && ruleExitActionTemplate.interfaceName === ruleTemplate.interfaceName) { - selectedThings.push(root.device.id); - createRuleAction(rule, ruleTemplate, selectedThings, rule.exitActions, root.device, ruleExitActionTemplate); + + for (var i = rule.exitActions.count; i < ruleTemplate.ruleExitActionTemplates.count; i++) { + var ruleExitActionTemplate = ruleTemplate.ruleExitActionTemplates.get(i); + + if (ruleExitActionTemplate.selectionMode === RuleActionTemplate.SelectionModeInterface) { + // TODO: Implement blacklist for interface based actions + var ruleExitAction = rule.exitActions.createNewRuleAction(); + ruleExitAction.interfaceName = ruleExitActionTemplate.interfaceName; + ruleExitAction.interfaceAction = ruleExitActionTemplate.interfaceAction; + for (var j = 0; j < ruleExitActionTemplate.ruleActionParamTemplates.count; j++) { + var ruleActionParam = ruleExitActionTemplate.ruleActionParamTemplates.get(j) + ruleExitAction.ruleActionParams.setRuleActionParam(ruleActionParam.paramName, ruleActionParam.value) + } + selectedInterfaces[ruleExitActionTemplate.selectionId] = ruleExitAction.interfaceName; + rule.exitActions.addRuleAction(ruleExitAction); + fillRuleFromTemplate(rule, ruleTemplate); + return; + } + + // Did we pick a thing for this index before? + if (ruleExitActionTemplate.selectionId in selectedThings) { + var device = engine.deviceManager.devices.getDevice(selectedThings[ruleExitActionTemplate.selectionId]); + createRuleAction(rule, ruleTemplate, rule.exitActions, device, ruleExitActionTemplate); + return; + } + + // Did we already use the thing we opened this page from? + if (!deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(ruleExitActionTemplate.interfaceName) >= 0 && ruleExitActionTemplate.interfaceName === ruleTemplate.interfaceName) { + selectedThings[ruleExitActionTemplate.selectionId] = root.device.id; + createRuleAction(rule, ruleTemplate, rule.exitActions, root.device, ruleExitActionTemplate); + return; + } + + // Ok, we need to pick a thing + var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [ruleExitActionTemplate.interfaceName]}); + page.thingSelected.connect(function(device) { + selectedThings[ruleExitActionTemplate.selectionId] = device.id; + createRuleAction(rule, ruleTemplate, rule.exitActions, device, ruleExitActionTemplate); + return; + }) + page.backPressed.connect(function() {rule.destroy(); root.done();}) return; } - // Ok, we need to pick a thing - var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [ruleExitActionTemplate.interfaceName]}); - page.thingSelected.connect(function(device) { - selectedThings.push(device.id); - createRuleAction(rule, ruleTemplate, selectedThings, rule.exitActions, device, ruleExitActionTemplate); - return; - }) - page.backPressed.connect(function() {rule.destroy(); root.done();}) - return; - } + // Now replace %i in title and action params with selectedThings[i].name + rule.name = ruleTemplate.ruleNameTemplate; + for (var selectionId in selectedThings) { + print("Replacing", selectionId, "with", selectedThings[selectionId], selectedInterfaces[selectionId]) + var device = engine.deviceManager.devices.getDevice(selectedThings[selectionId]); + rule.name = rule.name.replace("%" + selectionId, device.name) - // Now replace %i in title and action params with selectedThings[i].name - rule.name = ruleTemplate.ruleNameTemplate; - for (var i = 0; i < selectedThings.length; i++) { - var device = engine.deviceManager.devices.getDevice(selectedThings[i]); - rule.name = rule.name.arg(device.name) - - for (var j = 0; j < rule.actions.count; j++) { - var action = rule.actions.get(j); - for(var k = 0; k < action.ruleActionParams.count; k++) { - var actionParam = action.ruleActionParams.get(k); - print("replacing args", typeof actionParam.value) - if (typeof actionParam.value === "string") { - actionParam.value = actionParam.value.arg(device.name); + for (var j = 0; j < rule.actions.count; j++) { + var action = rule.actions.get(j); + for(var k = 0; k < action.ruleActionParams.count; k++) { + var actionParam = action.ruleActionParams.get(k); + print("replacing args", typeof actionParam.value) + if (typeof actionParam.value === "string") { + actionParam.value = actionParam.value.replace("%" + selectionId, device.name); + } + } + } + for (var j = 0; j < rule.exitActions.count; j++) { + var action = rule.exitActions.get(j); + for(var k = 0; k < action.ruleActionParams.count; k++) { + var actionParam = action.ruleActionParams.get(k); + if (typeof actionParam.value === "string") { + actionParam.value = actionParam.value.replace("%" + selectionId, device.name); + } } } } - for (var j = 0; j < rule.exitActions.count; j++) { - var action = rule.exitActions.get(j); - for(var k = 0; k < action.ruleActionParams.count; k++) { - var actionParam = action.ruleActionParams.get(k); - if (typeof actionParam.value === "string") { - actionParam.value = actionParam.value.arg(device.name); + for (selectionId in selectedInterfaces) { + rule.name = rule.name.replace("%" + selectionId, qsTr("any " + app.interfaceToDisplayName(selectedInterfaces[selectionId]))) + } + + print("Rule complete!") + engine.ruleManager.addRule(rule); + rule.destroy(); + root.done(); + } + + function fillStateEvaluatorFromTemplate(rule, ruleTemplate, stateEvaluator, stateEvaluatorTemplate) { + if (stateEvaluatorTemplate.stateDescriptorTemplate !== null && !deviceIsUsed(stateEvaluator.stateDescriptor.deviceId) && stateEvaluator.stateDescriptor.interfaceName.length === 0) { + // need to fill stateDescriptor + + 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.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; + stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; + selectedInterfaces[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] = stateEvaluator.stateDescriptor.interfaceName; + fillRuleFromTemplate(rule, ruleTemplate); + return true; + } + + // did we pick a thing for this index before? + if (stateEvaluatorTemplate.stateDescriptorTemplate.selectionId in selectedThings) { + var deviceId = selectedThings[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] + 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.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; + stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; + fillRuleFromTemplate(rule, ruleTemplate); + return true; + } + if (!deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName) >= 0 && stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName === ruleTemplate.interfaceName) { + stateEvaluator.stateDescriptor.deviceId = root.device.id; + stateEvaluator.stateDescriptor.stateTypeId = root.deviceClass.stateTypes.findByName(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceState).id + stateEvaluator.stateDescriptor.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; + stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; + selectedThings[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] = root.device.id; + fillRuleFromTemplate(rule, ruleTemplate); + return true; + } + 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}); + 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.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; + stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; + selectedThings[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] = device.id; + fillRuleFromTemplate(rule, ruleTemplate) + }) + page.onAnySelected.connect(function() { + stateEvaluator.stateDescriptor.interfaceName = stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName; + stateEvaluator.stateDescriptor.interfaceState = stateEvaluatorTemplate.stateDescriptorTemplate.interfaceState; + stateEvaluator.stateDescriptor.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; + stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; + selectedInterfaces[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] = stateEvaluator.stateDescriptor.interfaceName; + fillRuleFromTemplate(rule, ruleTemplate); + }) + page.backPressed.connect(function() {rule.destroy(); root.done();}) + return true; + } + stateEvaluator.stateOperator = stateEvaluatorTemplate.stateOperator; + if (stateEvaluatorTemplate.childEvaluatorTemplates.count > stateEvaluator.childEvaluators.count) { + var childEvaluator = rule.createStateEvaluator(); + var more = fillStateEvaluatorFromTemplate(rule, ruleTemplate, childEvaluator, stateEvaluatorTemplate.childEvaluatorTemplates.get(stateEvaluator.childEvaluators.count)) + stateEvaluator.childEvaluators.addStateEvaluator(childEvaluator); + return more; + } + return false; + } + + function createEventDescriptor(rule, ruleTemplate, device, eventDescriptorTemplate) { + 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 + var needsParams = false; + for (var j = 0; j < eventDescriptorTemplate.paramDescriptors.count; j++) { + var paramDescriptorTemplate = eventDescriptorTemplate.paramDescriptors.get(j); + if (paramDescriptorTemplate.value !== undefined) { + print("Adding operator:", paramDescriptorTemplate.operatorType) + eventDescriptor.paramDescriptors.setParamDescriptorByName(paramDescriptorTemplate.paramName, paramDescriptorTemplate.value, paramDescriptorTemplate.operatorType); + } else { + needsParams = true; + } + } + if (needsParams) { + var page = pageStack.push(Qt.resolvedUrl("SelectEventDescriptorParamsPage.qml"), { eventDescriptor: eventDescriptor }) + page.completed.connect(function() { + rule.eventDescriptors.addEventDescriptor(eventDescriptor); + fillRuleFromTemplate(rule, ruleTemplate); + }) + page.onBackPressed.connect(function() { + eventDescriptor.destroy(); + pageStack.pop(); + }); + return; + } + rule.eventDescriptors.addEventDescriptor(eventDescriptor); + fillRuleFromTemplate(rule, ruleTemplate); + } + + function createRuleAction(rule, ruleTemplate, ruleActions, device, ruleActionTemplate) { + var ruleAction = ruleActions.createNewRuleAction(); + var deviceClass = engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); + ruleAction.deviceId = device.id; + print("Creating action", ruleActionTemplate.interfaceAction, "on device class", deviceClass.displayName) + ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleActionTemplate.interfaceAction).id + for (var j = 0; j < ruleActionTemplate.ruleActionParamTemplates.count; j++) { + var ruleActionParamTemplate = ruleActionTemplate.ruleActionParamTemplates.get(j) + var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId); + var paramType = actionType.paramTypes.findByName(ruleActionParamTemplate.paramName); + if (ruleActionParamTemplate.value !== undefined) { + ruleAction.ruleActionParams.setRuleActionParam(paramType.id, ruleActionParamTemplate.value) + } else if (ruleActionParamTemplate.eventInterface && ruleActionParamTemplate.eventName && ruleActionParamTemplate.eventParamName) { + print("should create rule action param from interface", ruleActionParamTemplate.eventInterface, ruleActionParamTemplate.eventName, ruleActionParamTemplate.eventParamName) + // find matching eventDescriptor + var eventDescriptorTemplate = null; + 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) { + eventDescriptorTemplate = tmp; + break; + } } - } - } - } - - print("Rule complete!") - engine.ruleManager.addRule(rule); - rule.destroy(); - root.done(); - } - - function fillStateEvaluatorFromTemplate(rule, ruleTemplate, stateEvaluator, stateEvaluatorTemplate, selectedThings) { - if (stateEvaluatorTemplate.stateDescriptorTemplate !== null && selectedThings.indexOf(stateEvaluator.stateDescriptor.deviceId) === -1 && stateEvaluator.stateDescriptor.interfaceName.length === 0) { - // need to fill stateDescriptor - - 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.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; - stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; - fillRuleFromTemplate(rule, ruleTemplate, selectedThings); - return true; - } - - // did we pick a thing for this index before? - if (selectedThings.length > stateEvaluatorTemplate.stateDescriptorTemplate.selectionId) { - var deviceId = selectedThings[stateEvaluatorTemplate.stateDescriptorTemplate.selectionId] - 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.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; - stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; - fillRuleFromTemplate(rule, ruleTemplate, selectedThings); - return true; - } - if (selectedThings.indexOf(root.device.id) === -1 && root.deviceClass.interfaces.indexOf(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName) >= 0 && stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName === ruleTemplate.interfaceName) { - stateEvaluator.stateDescriptor.deviceId = root.device.id; - stateEvaluator.stateDescriptor.stateTypeId = root.deviceClass.stateTypes.findByName(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceState).id - stateEvaluator.stateDescriptor.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; - stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; - selectedThings.push(root.device.id); - fillRuleFromTemplate(rule, ruleTemplate, selectedThings); - return true; - } - 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}); - 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.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; - stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; - selectedThings.push(device.id); - fillRuleFromTemplate(rule, ruleTemplate, selectedThings) - }) - page.onAnySelected.connect(function() { - stateEvaluator.stateDescriptor.interfaceName = stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName; - stateEvaluator.stateDescriptor.interfaceState = stateEvaluatorTemplate.stateDescriptorTemplate.interfaceState; - stateEvaluator.stateDescriptor.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator; - stateEvaluator.stateDescriptor.value = stateEvaluatorTemplate.stateDescriptorTemplate.value; - fillRuleFromTemplate(rule, ruleTemplate, selectedThings); - }) - page.backPressed.connect(function() {rule.destroy(); root.done();}) - return true; - } - stateEvaluator.stateOperator = stateEvaluatorTemplate.stateOperator; - if (stateEvaluatorTemplate.childEvaluatorTemplates.count > stateEvaluator.childEvaluators.count) { - var childEvaluator = rule.createStateEvaluator(); - var more = fillStateEvaluatorFromTemplate(rule, ruleTemplate, childEvaluator, stateEvaluatorTemplate.childEvaluatorTemplates.get(stateEvaluator.childEvaluators.count)) - stateEvaluator.childEvaluators.addStateEvaluator(childEvaluator); - return more; - } - return false; - } - - function createEventDescriptor(rule, ruleTemplate, selectedThings, device, eventDescriptorTemplate) { - 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 - var needsParams = false; - for (var j = 0; j < eventDescriptorTemplate.paramDescriptors.count; j++) { - var paramDescriptorTemplate = eventDescriptorTemplate.paramDescriptors.get(j); - if (paramDescriptorTemplate.value !== undefined) { - print("Adding operator:", paramDescriptorTemplate.operatorType) - eventDescriptor.paramDescriptors.setParamDescriptorByName(paramDescriptorTemplate.paramName, paramDescriptorTemplate.value, paramDescriptorTemplate.operatorType); - } else { - needsParams = true; - } - } - if (needsParams) { - var page = pageStack.push(Qt.resolvedUrl("SelectEventDescriptorParamsPage.qml"), { eventDescriptor: eventDescriptor }) - page.completed.connect(function() { - rule.eventDescriptors.addEventDescriptor(eventDescriptor); - fillRuleFromTemplate(rule, ruleTemplate, selectedThings); - }) - page.onBackPressed.connect(function() { - eventDescriptor.destroy(); - pageStack.pop(); - }); - return; - } - rule.eventDescriptors.addEventDescriptor(eventDescriptor); - fillRuleFromTemplate(rule, ruleTemplate, selectedThings); - } - - function createRuleAction(rule, ruleTemplate, selectedThings, ruleActions, device, ruleActionTemplate) { - var ruleAction = ruleActions.createNewRuleAction(); - var deviceClass = engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); - ruleAction.deviceId = device.id; - ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleActionTemplate.interfaceAction).id - for (var j = 0; j < ruleActionTemplate.ruleActionParamTemplates.count; j++) { - var ruleActionParamTemplate = ruleActionTemplate.ruleActionParamTemplates.get(j) - var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId); - var paramType = actionType.paramTypes.findByName(ruleActionParamTemplate.paramName); - if (ruleActionParamTemplate.value !== undefined) { - ruleAction.ruleActionParams.setRuleActionParam(paramType.id, ruleActionParamTemplate.value) - } else if (ruleActionParamTemplate.eventInterface && ruleActionParamTemplate.eventName && ruleActionParamTemplate.eventParamName) { - print("should create rule action param from interface", ruleActionParamTemplate.eventInterface, ruleActionParamTemplate.eventName, ruleActionParamTemplate.eventParamName) - // find matching eventDescriptor - var eventDescriptorTemplate = null; - 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) { - eventDescriptorTemplate = tmp; - break; + if (eventDescriptorTemplate === null) { + console.warn("Unable to find an event matching the criteria:", ruleActionParamTemplate.eventInterface, ruleActionParamTemplate.eventName, ruleActionParamTemplate.eventParamName) + break } - } - if (eventDescriptorTemplate === null) { - console.warn("Unable to find an event matching the criteria:", ruleActionParamTemplate.eventInterface, ruleActionParamTemplate.eventName, ruleActionParamTemplate.eventParamName) - break - } - print("selected device:", selectedThings, eventDescriptorTemplate.selectionId) - var eventDevice = engine.deviceManager.devices.getDevice(selectedThings[eventDescriptorTemplate.selectionId]) - var eventDeviceClass = engine.deviceManager.deviceClasses.getDeviceClass(eventDevice.deviceClassId); - var eventType = eventDeviceClass.eventTypes.findByName(ruleActionParamTemplate.eventName); - var eventParamType = eventType.paramTypes.findByName(ruleActionParamTemplate.eventParamName); + print("selected device:", selectedThings, eventDescriptorTemplate.selectionId) + var eventDevice = engine.deviceManager.devices.getDevice(selectedThings[eventDescriptorTemplate.selectionId]) + var eventDeviceClass = engine.deviceManager.deviceClasses.getDeviceClass(eventDevice.deviceClassId); + var eventType = eventDeviceClass.eventTypes.findByName(ruleActionParamTemplate.eventName); + var eventParamType = eventType.paramTypes.findByName(ruleActionParamTemplate.eventParamName); + + ruleAction.ruleActionParams.setRuleActionParamEvent(paramType.id, eventType.id, eventParamType.id) + } else { + console.warn("Invalid RuleActionParamTemplate. Has neither value nor event spec") + } - ruleAction.ruleActionParams.setRuleActionParamEvent(paramType.id, eventType.id, eventParamType.id) - } else { - console.warn("Invalid RuleActionParamTemplate. Has neither value nor event spec") } - + ruleActions.addRuleAction(ruleAction); + fillRuleFromTemplate(rule, ruleTemplate); + } + + function deviceIsUsed(deviceId) { + for (var key in selectedThings) { + if (selectedThings.hasOwnProperty(key) && selectedThings[key] === deviceId) { + return true; + } + } + return false; } - ruleActions.addRuleAction(ruleAction); - fillRuleFromTemplate(rule, ruleTemplate, selectedThings); } header: GuhHeader { @@ -343,8 +372,7 @@ Page { onClicked: { var ruleTemplate = ruleTemplatesModel.get(index); - var rule = engine.ruleManager.createNewRule(); - root.fillRuleFromTemplate(rule, ruleTemplate) + root.createRuleFromTemplate(ruleTemplate) } } } diff --git a/nymea-app/ui/magic/SelectThingPage.qml b/nymea-app/ui/magic/SelectThingPage.qml index 20a700ab..dfd2f0b1 100644 --- a/nymea-app/ui/magic/SelectThingPage.qml +++ b/nymea-app/ui/magic/SelectThingPage.qml @@ -48,6 +48,11 @@ Page { ColumnLayout { anchors.fill: parent + ListFilterInput { + id: filterInput + Layout.fillWidth: true + } + MeaListItemDelegate { Layout.fillWidth: true text: qsTr("Any %1").arg(app.interfaceToDisplayName(root.shownInterfaces[0])) @@ -58,10 +63,6 @@ Page { } ThinDivider { visible: root.allowSelectAny } - ListFilterInput { - id: filterInput - Layout.fillWidth: true - } ListView { Layout.fillWidth: true