Improve rule creation

This commit is contained in:
Michael Zanetti 2019-08-31 00:12:25 +02:00
parent 8d8b72790b
commit 176baa8ede
29 changed files with 315 additions and 220 deletions

View File

@ -45,7 +45,7 @@ DeviceManager::DeviceManager(JsonRpcClient* jsonclient, QObject *parent) :
qWarning() << "received an event from a device we don't know..." << deviceId << event;
return;
}
qDebug() << "Event received" << deviceId.toString() << eventTypeId.toString();
// qDebug() << "Event received" << deviceId.toString() << eventTypeId.toString();
dev->eventTriggered(eventTypeId.toString(), event.value("params").toMap());
emit eventTriggered(deviceId.toString(), eventTypeId.toString(), event.value("params").toMap());

View File

@ -156,7 +156,6 @@ signals:
private:
Q_INVOKABLE void notificationReceived(const QVariantMap &data) {
qDebug() << "event rece" << data;
emit eventReceived(data.value("params").toMap().value("event").toMap());
}

View File

@ -251,6 +251,7 @@ bool DevicesProxy::filterAcceptsRow(int source_row, const QModelIndex &source_pa
}
}
DeviceClass *deviceClass = m_engine->deviceManager()->deviceClasses()->getDeviceClass(device->deviceClassId());
// qDebug() << "Checking device" << deviceClass->name() << deviceClass->interfaces();
if (!m_shownInterfaces.isEmpty()) {
bool foundMatch = false;
foreach (const QString &filterInterface, m_shownInterfaces) {

View File

@ -35,3 +35,13 @@ ParamDescriptors *EventDescriptorTemplate::paramDescriptors() const
{
return m_paramDescriptors;
}
QStringList EventDescriptorTemplates::interfaces() const
{
QStringList ret;
for (int i = 0; i < m_list.count(); i++) {
ret.append(m_list.at(i)->interfaceName());
}
ret.removeDuplicates();
return ret;
}

View File

@ -42,9 +42,11 @@ class EventDescriptorTemplates: public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
Q_PROPERTY(QStringList interfaces READ interfaces CONSTANT)
public:
EventDescriptorTemplates(QObject *parent = nullptr): QAbstractListModel(parent) {}
QStringList interfaces() const;
int rowCount(const QModelIndex &parent = QModelIndex()) const override { Q_UNUSED(parent); return m_list.count(); }
QVariant data(const QModelIndex &index, int role) const override { Q_UNUSED(index); Q_UNUSED(role); return QVariant(); }
@ -63,6 +65,8 @@ public:
return m_list.at(index);
}
signals:
void countChanged();

View File

@ -36,3 +36,13 @@ RuleActionParamTemplates *RuleActionTemplate::ruleActionParamTemplates() const
{
return m_ruleActionParamTemplates;
}
QStringList RuleActionTemplates::interfaces() const
{
QStringList ret;
for (int i = 0; i < m_list.count(); i++) {
ret.append(m_list.at(i)->interfaceName());
}
ret.removeDuplicates();
return ret;
}

View File

@ -44,10 +44,12 @@ class RuleActionTemplates: public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
Q_PROPERTY(QStringList interfaces READ interfaces CONSTANT)
public:
RuleActionTemplates(QObject *parent = nullptr): QAbstractListModel(parent) {}
int rowCount(const QModelIndex &parent = QModelIndex()) const override { Q_UNUSED(parent); return m_list.count(); }
QVariant data(const QModelIndex &index, int role) const override { Q_UNUSED(index); Q_UNUSED(role); return QVariant(); }
QStringList interfaces() const;
void addRuleActionTemplate(RuleActionTemplate* ruleActionTemplate) {
ruleActionTemplate->setParent(this);

View File

@ -14,11 +14,6 @@ RuleTemplate::RuleTemplate(const QString &interfaceName, const QString &descript
{
}
QString RuleTemplate::interfaceName() const
{
return m_interfaceName;
}
QString RuleTemplate::description() const
{
return m_description;
@ -29,6 +24,18 @@ QString RuleTemplate::ruleNameTemplate() const
return m_ruleNameTemplate;
}
QStringList RuleTemplate::interfaces() const
{
QStringList ret;
ret.append(m_eventDescriptorTemplates->interfaces());
if (m_stateEvaluatorTemplate) {
ret.append(m_stateEvaluatorTemplate->interfaces());
}
ret.append(m_ruleActionTemplates->interfaces());
ret.append(m_ruleExitActionTemplates->interfaces());
return ret;
}
EventDescriptorTemplates *RuleTemplate::eventDescriptorTemplates() const
{
return m_eventDescriptorTemplates;

View File

@ -10,9 +10,9 @@ class StateEvaluatorTemplate;
class RuleTemplate : public QObject
{
Q_OBJECT
Q_PROPERTY(QString interfaceName READ interfaceName CONSTANT)
Q_PROPERTY(QString description READ description CONSTANT)
Q_PROPERTY(QString ruleNameTemplate READ ruleNameTemplate CONSTANT)
Q_PROPERTY(QStringList interfaces READ interfaces CONSTANT)
Q_PROPERTY(EventDescriptorTemplates* eventDescriptorTemplates READ eventDescriptorTemplates CONSTANT)
Q_PROPERTY(StateEvaluatorTemplate* stateEvaluatorTemplate READ stateEvaluatorTemplate CONSTANT)
Q_PROPERTY(RuleActionTemplates* ruleActionTemplates READ ruleActionTemplates CONSTANT)
@ -21,9 +21,9 @@ class RuleTemplate : public QObject
public:
explicit RuleTemplate(const QString &interfaceName, const QString &description, const QString &ruleNameTemplate, QObject *parent = nullptr);
QString interfaceName() const;
QString description() const;
QString ruleNameTemplate() const;
QStringList interfaces() const;
EventDescriptorTemplates* eventDescriptorTemplates() const;
StateEvaluatorTemplate* stateEvaluatorTemplate() const;

View File

@ -8,6 +8,7 @@
#include "types/ruleactionparam.h"
#include "types/ruleactionparams.h"
#include "devicesproxy.h"
#include <QDebug>
#include <QDir>
@ -167,6 +168,8 @@ QVariant RuleTemplates::data(const QModelIndex &index, int role) const
switch (role) {
case RoleDescription:
return m_list.at(index.row())->description();
case RoleInterfaces:
return m_list.at(index.row())->interfaces();
}
return QVariant();
}
@ -175,6 +178,7 @@ QHash<int, QByteArray> RuleTemplates::roleNames() const
{
QHash<int, QByteArray> roles;
roles.insert(RoleDescription, "description");
roles.insert(RoleInterfaces, "interfaces");
return roles;
}
@ -193,40 +197,38 @@ 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->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)->deviceClass()->interfaces().contains(toBeFound)) {
found = true;
break;
}
}
if (!found) {
qDebug() << "Filtering out" << t->description() << "because required devices are not provided in filter proxy";
return false;
}
}
}
if (!m_filterInterfaceNames.isEmpty()) {
if (!m_filterInterfaceNames.contains(t->interfaceName())) {
bool found = false;
foreach (const QString toBeFound, m_filterInterfaceNames) {
if (t->interfaces().contains(toBeFound)) {
found = true;
break;
}
}
if (!found) {
return false;
}
// bool found = false;
// for (int i = 0; i < t->eventDescriptorTemplates()->rowCount(); i++) {
// if (m_filterInterfaceNames.contains(t->eventDescriptorTemplates()->get(i)->interfaceName())) {
// found = true;
// break;
// }
// }
// if (!found && t->stateEvaluatorTemplate() && stateEvaluatorTemplateContainsInterface(t->stateEvaluatorTemplate(), m_filterInterfaceNames)) {
// found = true;
// }
// if (!found) {
// for (int i = 0; i < t->ruleActionTemplates()->rowCount(); i++) {
// if (m_filterInterfaceNames.contains(t->ruleActionTemplates()->get(i)->interfaceName())) {
// found = true;
// break;
// }
// }
// }
// if (!found) {
// for (int i = 0; i < t->ruleExitActionTemplates()->rowCount(); i++) {
// if (m_filterInterfaceNames.contains(t->ruleExitActionTemplates()->get(i)->interfaceName())) {
// found = true;
// break;
// }
// }
// }
// if (!found) {
// return false;
// }
}
return true;
}

View File

@ -5,6 +5,7 @@
class RuleTemplate;
class StateEvaluatorTemplate;
class DevicesProxy;
class RuleTemplates : public QAbstractListModel
{
@ -12,7 +13,8 @@ class RuleTemplates : public QAbstractListModel
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
public:
enum Roles {
RoleDescription
RoleDescription,
RoleInterfaces
};
Q_ENUM(Roles)
@ -39,12 +41,16 @@ class RuleTemplatesFilterModel: public QSortFilterProxyModel
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
Q_PROPERTY(RuleTemplates* ruleTemplates READ ruleTemplates WRITE setRuleTemplates NOTIFY ruleTemplatesChanged)
Q_PROPERTY(QStringList filterInterfaceNames READ filterInterfaceNames WRITE setFilterInterfaceNames NOTIFY filterInterfaceNamesChanged)
Q_PROPERTY(DevicesProxy* filterByDevices READ filterByDevices WRITE setFilterByDevices NOTIFY filterByDevicesChanged)
public:
RuleTemplatesFilterModel(QObject *parent = nullptr): QSortFilterProxyModel(parent) {}
RuleTemplates* ruleTemplates() const { return m_ruleTemplates; }
void setRuleTemplates(RuleTemplates* ruleTemplates) { if (m_ruleTemplates != ruleTemplates) { m_ruleTemplates = ruleTemplates; setSourceModel(ruleTemplates); emit ruleTemplatesChanged(); invalidateFilter(); emit countChanged();}}
QStringList filterInterfaceNames() const { return m_filterInterfaceNames; }
void setFilterInterfaceNames(const QStringList &filterInterfaceNames) { if (m_filterInterfaceNames != filterInterfaceNames) { m_filterInterfaceNames = filterInterfaceNames; emit filterInterfaceNamesChanged(); invalidateFilter(); emit countChanged(); }}
DevicesProxy* filterByDevices() const { return m_filterDevicesProxy; }
void setFilterByDevices(DevicesProxy* filterDevicesProxy) {if (m_filterDevicesProxy != filterDevicesProxy) { m_filterDevicesProxy = filterDevicesProxy; emit filterByDevicesChanged(); invalidateFilter(); }}
Q_INVOKABLE RuleTemplate* get(int index) {
if (index < 0 || index >= rowCount()) {
return nullptr;
@ -57,10 +63,12 @@ protected:
signals:
void ruleTemplatesChanged();
void filterInterfaceNamesChanged();
void filterByDevicesChanged();
void countChanged();
private:
RuleTemplates* m_ruleTemplates = nullptr;
QStringList m_filterInterfaceNames;
DevicesProxy* m_filterDevicesProxy = nullptr;
};
#endif // RULETEMPLATES_H

View File

@ -23,3 +23,19 @@ StateEvaluatorTemplates *StateEvaluatorTemplate::childEvaluatorTemplates() const
{
return m_childEvaluatorTemplates;
}
QStringList StateEvaluatorTemplate::interfaces() const
{
QStringList ret;
if (m_stateDescriptorTemplate) {
ret.append(stateDescriptorTemplate()->interfaceName());
}
for (int i = 0; i < m_childEvaluatorTemplates->rowCount(); i++) {
ret.append(m_childEvaluatorTemplates->get(i)->interfaces());
}
ret.removeDuplicates();
return ret;
}

View File

@ -13,6 +13,7 @@ class StateEvaluatorTemplate : public QObject
Q_PROPERTY(StateDescriptorTemplate* stateDescriptorTemplate READ stateDescriptorTemplate CONSTANT)
Q_PROPERTY(StateOperator stateOperator READ stateOperator CONSTANT)
Q_PROPERTY(StateEvaluatorTemplates* childEvaluatorTemplates READ childEvaluatorTemplates CONSTANT)
Q_PROPERTY(QStringList interfaces READ interfaces CONSTANT)
public:
enum StateOperator {
@ -26,6 +27,7 @@ public:
StateDescriptorTemplate* stateDescriptorTemplate() const;
StateOperator stateOperator() const;
StateEvaluatorTemplates* childEvaluatorTemplates() const;
QStringList interfaces() const;
private:
StateDescriptorTemplate* m_stateDescriptorTemplate = nullptr;

View File

@ -1,6 +1,8 @@
#include "paramdescriptors.h"
#include "paramdescriptor.h"
#include <QDebug>
ParamDescriptors::ParamDescriptors(QObject *parent) : QAbstractListModel(parent)
{
@ -99,6 +101,30 @@ void ParamDescriptors::clear()
emit countChanged();
}
ParamDescriptor *ParamDescriptors::getParamDescriptor(const QString &paramTypeId) const
{
qDebug() << "getParamDescriptor" << paramTypeId;
for (int i = 0; i < m_list.count(); i++) {
qDebug() << "have param descriptor:" << m_list.at(i)->paramTypeId();
if (m_list.at(i)->paramTypeId() == paramTypeId) {
return m_list.at(i);
}
}
return nullptr;
}
ParamDescriptor *ParamDescriptors::getParamDescriptorByName(const QString &paramName) const
{
qDebug() << "getParamDescriptorByName" << paramName;
for (int i = 0; i < m_list.count(); i++) {
qDebug() << "have param descriptor:" << m_list.at(i)->paramName();
if (m_list.at(i)->paramName() == paramName) {
return m_list.at(i);
}
}
return nullptr;
}
bool ParamDescriptors::operator==(ParamDescriptors *other) const
{
if (rowCount() != other->rowCount()) {

View File

@ -42,6 +42,9 @@ public:
Q_INVOKABLE void setParamDescriptorByName(const QString &paramName, const QVariant &value, ValueOperator operatorType);
Q_INVOKABLE void clear();
Q_INVOKABLE ParamDescriptor *getParamDescriptor(const QString &paramTypeId) const;
Q_INVOKABLE ParamDescriptor *getParamDescriptorByName(const QString &paramName) const;
bool operator==(ParamDescriptors *other) const;
signals:

View File

@ -194,5 +194,6 @@
<file>ui/components/NavigationPad.qml</file>
<file>ui/components/KeypadButton.qml</file>
<file>ui/devicepages/DoorbellDevicePage.qml</file>
<file>ui/magic/NewMagicPage.qml</file>
</qresource>
</RCC>

View File

@ -1,31 +1,15 @@
{
"templates": [
{
"interfaceName": "simplemultibutton",
"description": "Switch a light",
"ruleNameTemplate": "%0 switches %1",
"description": "Turn on a light",
"ruleNameTemplate": "%0 turns on %1",
"eventDescriptorTemplates": [
{
"interfaceName": "simplemultibutton",
"interfaceName": "button",
"interfaceEvent": "pressed",
"selectionId": 0,
"params": [
{
"name": "buttonName"
}
]
"selectionId": 0
}
],
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "light",
"interfaceState": "power",
"operator": "ValueOperatorEquals",
"value": false,
"selectionId": 1,
"selectionMode": "SelectionModeDevice"
}
},
"ruleActionTemplates": [
{
"interfaceName": "light",
@ -39,8 +23,19 @@
}
]
}
]
},
{
"description": "Turn off a light",
"ruleNameTemplate": "%0 turns off %1",
"eventDescriptorTemplates": [
{
"interfaceName": "button",
"interfaceEvent": "pressed",
"selectionId": 0
}
],
"ruleExitActionTemplates": [
"ruleActionTemplates": [
{
"interfaceName": "light",
"interfaceAction": "power",
@ -56,12 +51,11 @@
]
},
{
"interfaceName": "simplebutton",
"description": "Switch a light",
"ruleNameTemplate": "%0 switches %1",
"eventDescriptorTemplates": [
{
"interfaceName": "simplebutton",
"interfaceName": "button",
"interfaceEvent": "pressed",
"selectionId": 0
}
@ -106,44 +100,12 @@
]
},
{
"interfaceName": "simplemultibutton",
"interfaceName": "button",
"description": "Turn off all lights",
"ruleNameTemplate": "Turn off everything with %0",
"eventDescriptorTemplates": [
{
"interfaceName": "simplemultibutton",
"interfaceEvent": "pressed",
"selectionId": 0,
"selectionMode": "SelectionModeDevice",
"params": [
{
"name": "buttonName"
}
]
}
],
"ruleActionTemplates": [
{
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"selectionMode": "SelectionModeInterface",
"params": [
{
"name": "power",
"value": false
}
]
}
]
},
{
"interfaceName": "simplebutton",
"description": "Turn off all lights",
"ruleNameTemplate": "Turn off everything with %0",
"eventDescriptorTemplates": [
{
"interfaceName": "simplebutton",
"interfaceName": "button",
"interfaceEvent": "pressed",
"selectionId": 0,
"selectionMode": "SelectionModeDevice"

View File

@ -15,7 +15,7 @@
},
"ruleActionTemplates": [
{
"interfaceName": "power",
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"params": [
@ -28,7 +28,7 @@
],
"ruleExitActionTemplates": [
{
"interfaceName": "power",
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"params": [
@ -43,7 +43,7 @@
{
"interfaceName": "daylightsensor",
"description": "Turn on a light when it gets dark outside.",
"ruleNameTemplate": "Turn on %1 it gets dark outside (%0).",
"ruleNameTemplate": "Turn on %1 when it gets dark outside (%0).",
"eventDescriptorTemplates": [
{
"interfaceName": "daylightsensor",

View File

@ -1,7 +1,6 @@
{
"templates": [
{
"interfaceName": "doorbell",
"description": "Alert on doorbell ring",
"ruleNameTemplate": "Alert %1 when someone is at %0",
"eventDescriptorTemplates": [

View File

@ -1,85 +1,3 @@
{
"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"
}
]
}
]
}
]
}

View File

@ -1,8 +1,7 @@
{
"templates": [
{
"interfaceName": "notifications",
"description": "Notify me when a device runs out of battery",
"description": "Notify me when a device runs out of battery.",
"ruleNameTemplate": "Low battery alert for %0",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
@ -33,8 +32,38 @@
]
},
{
"interfaceName": "notifications",
"description": "Notify me when a thing gets disconnected",
"description": "Notify me when something runs dry.",
"ruleNameTemplate": "Notify %1 when %0 runs dry",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "moisturesensor",
"interfaceState": "moisture",
"operator": "ValueOperatorLess",
"selectionId": 0,
"value": 20
}
},
"ruleActionTemplates": [
{
"interfaceName": "notifications",
"interfaceAction": "notify",
"selectionId": 1,
"selectionMode": "SelectionModeDevice",
"params": [
{
"name": "title",
"value": "Water alert"
},
{
"name": "body",
"value": "%0 runs dry"
}
]
}
]
},
{
"description": "Notify me when a thing gets disconnected.",
"ruleNameTemplate": "Disconnect alert for %0",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
@ -67,7 +96,7 @@
},
{
"interfaceName": "notifications",
"description": "Notify me when a thing connects",
"description": "Notify me when a thing connects.",
"ruleNameTemplate": "Connection notification for %0",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
@ -88,7 +117,7 @@
"params": [
{
"name": "title",
"value": "Thin connected"
"value": "Thing connected"
},
{
"name": "body",

View File

@ -2,8 +2,8 @@
"templates": [
{
"interfaceName": "presencesensor",
"description": "Turn on something while this device is present...",
"ruleNameTemplate": "Turn on %1 while %0 is present",
"description": "Turn on something while being present.",
"ruleNameTemplate": "Turn on %1 while %0 reports presence",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "presencesensor",
@ -42,8 +42,8 @@
},
{
"interfaceName": "presencesensor",
"description": "Turn off something when this device leaves...",
"ruleNameTemplate": "Turn off %1 when %0 leaves",
"description": "Turn off something when leaving.",
"ruleNameTemplate": "Turn off %1 when %0 reports leaving",
"eventDescriptorTemplates": [
{
"interfaceName": "presencesensor",
@ -74,8 +74,8 @@
},
{
"interfaceName": "presencesensor",
"description": "Turn off everything when this device leaves...",
"ruleNameTemplate": "Turn off everything when %0 leaves",
"description": "Turn off everything when leaving.",
"ruleNameTemplate": "Turn off everything when %0 reports leaving",
"eventDescriptorTemplates": [
{
"interfaceName": "presencesensor",
@ -107,8 +107,8 @@
},
{
"interfaceName": "presencesensor",
"description": "Turn off all lights when this device leaves...",
"ruleNameTemplate": "Turn off all lights when %0 leaves",
"description": "Turn off all lights when leaving.",
"ruleNameTemplate": "Turn off all lights when %0 reports leaving",
"eventDescriptorTemplates": [
{
"interfaceName": "presencesensor",
@ -140,8 +140,8 @@
},
{
"interfaceName": "presencesensor",
"description": "Turn on something when this device arrives...",
"ruleNameTemplate": "Turn on %1 when %0 arrives",
"description": "Turn on something when arriving.",
"ruleNameTemplate": "Turn on %1 when %0 reports arriving",
"eventDescriptorTemplates": [
{
"interfaceName": "presencesensor",

View File

@ -1,7 +1,6 @@
{
"templates": [
{
"interfaceName": "",
"description": "",
"ruleNameTemplate": "%0 ...",
"eventDescriptorTemplates": [ // optional

View File

@ -18,7 +18,32 @@ Page {
}
}
RuleTemplatesFilterModel {
id: ruleTemplatesModel
ruleTemplates: RuleTemplates {}
readonly property var deviceClass: device ? engine.deviceManager.deviceClasses.getDeviceClass(root.device.deviceClassId) : null
filterByDevices: DevicesProxy { engine: _engine }
filterInterfaceNames: deviceClass ? deviceClass.interfaces : []
}
function addRule() {
if (ruleTemplatesModel.count > 0) {
d.editRulePage = pageStack.push(Qt.resolvedUrl("magic/NewThingMagicPage.qml"))
d.editRulePage.done.connect(function() {
print("add rule done")
pageStack.pop(root);
})
d.editRulePage.manualCreation.connect(function() {
pageStack.pop(root);
manualAddRule();
})
} else {
manualAddRule();
}
}
function manualAddRule() {
var newRule = engine.ruleManager.createNewRule();
d.editRulePage = pageStack.push(Qt.resolvedUrl("magic/EditRulePage.qml"), {rule: newRule });
d.editRulePage.StackView.onRemoved.connect(function() {
@ -41,20 +66,19 @@ Page {
Connections {
target: engine.ruleManager
onAddRuleReply: {
d.editRulePage.busy = false;
if (ruleError == "RuleErrorNoError") {
// print("should tag rule now:", d.editRulePage.rule.id, d.editRulePage.ruleIcon, d.editRulePage.ruleColor)
engine.tagsManager.tagRule(ruleId, "color", d.editRulePage.ruleColor)
engine.tagsManager.tagRule(ruleId, "icon", d.editRulePage.ruleIcon)
pageStack.pop();
// engine.tagsManager.tagRule(ruleId, "color", d.editRulePage.ruleColor)
// engine.tagsManager.tagRule(ruleId, "icon", d.editRulePage.ruleIcon)
pageStack.pop(root);
} else {
var popup = errorDialog.createObject(app, {errorCode: ruleError })
popup.open();
}
d.editRulePage.busy = false;
}
onEditRuleReply: {
d.editRulePage.busy = false;
if (ruleError == "RuleErrorNoError") {
// print("should tag rule now:", d.editRulePage.ruleIcon, d.editRulePage.ruleColor)
engine.tagsManager.tagRule(d.editRulePage.rule.id, "color", d.editRulePage.ruleColor)
@ -64,6 +88,7 @@ Page {
var popup = errorDialog.createObject(app, {errorCode: ruleError })
popup.open();
}
d.editRulePage.busy = false;
}
}

View File

@ -147,6 +147,7 @@ ApplicationWindow {
case "light":
case "colorlight":
case "dimmablelight":
case "colortemperaturelight":
return Qt.resolvedUrl("images/light-on.svg")
case "sensor":
return Qt.resolvedUrl("images/sensors.svg")
@ -232,6 +233,8 @@ ApplicationWindow {
return Qt.resolvedUrl("images/notification.svg")
case "connectable":
return Qt.resolvedUrl("images/stock_link.svg")
case "power":
return Qt.resolvedUrl("images/system-shutdown.svg")
default:
console.warn("InterfaceToIcon: Unhandled interface", name)
}
@ -293,6 +296,17 @@ ApplicationWindow {
return qsTr("doorbell")
case "alert":
return qsTr("alert")
case "simplemultibutton":
case "simplebutton":
return qsTr("button")
case "accesscotrol":
return qsTr("access control")
case "smartmeter":
case "smartmeterproducer":
case "smartmeterconsumer":
case "extendedsmartmeterproducer":
case "extendedsmartmeterconsumer":
return qsTr("smart meter");
default:
console.warn("Unhandled interfaceToDisplayName:", name)
}

View File

@ -27,6 +27,7 @@ Page {
id: ruleTemplatesModel
ruleTemplates: RuleTemplates {}
readonly property var deviceClass: device ? engine.deviceManager.deviceClasses.getDeviceClass(root.device.deviceClassId) : null
filterByDevices: DevicesProxy { engine: _engine }
filterInterfaceNames: deviceClass ? deviceClass.interfaces : []
}

View File

@ -0,0 +1,37 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import Nymea 1.0
import "../components"
Page {
id: root
header: NymeaHeader {
text: qsTr("New magic")
onBackPressed: pageStack.pop()
}
RuleTemplates {
id: ruleTemplates
}
ColumnLayout {
anchors.fill: parent
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: RuleTemplatesFilterModel {
ruleTemplates: ruleTemplates
}
delegate: NymeaListItemDelegate {
width: parent.width
text: model.description
}
}
}
}

View File

@ -7,8 +7,8 @@ import "../components"
Page {
id: root
property var device: null
readonly property var deviceClass: device ? engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
property Device device: null
readonly property DeviceClass deviceClass: device ? device.deviceClass : null
property bool busy: false
signal done();
@ -27,7 +27,7 @@ Page {
property var selectedInterfaces: ({})
function fillRuleFromTemplate(rule, ruleTemplate) {
print("Filling rule")
print("***** Filling rule")
// Fill in all EventDescriptors
for (var i = rule.eventDescriptors.count; i < ruleTemplate.eventDescriptorTemplates.count; i++) {
@ -36,17 +36,20 @@ Page {
// 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]);
print("Already have a device for selectionId", eventDescriptorTemplate.selectionId, ":", device.name)
createEventDescriptor(rule, ruleTemplate, 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 (!deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(eventDescriptorTemplate.interfaceName) >= 0 && eventDescriptorTemplate.interfaceName === ruleTemplate.interfaceName) {
if (root.device && !deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(eventDescriptorTemplate.interfaceName) >= 0) {
print("Root device is matching and not used. Using for selectionId", eventDescriptorTemplate.selectionId, ":", root.device.name)
selectedThings[eventDescriptorTemplate.selectionId] = root.device.id;
createEventDescriptor(rule, ruleTemplate, root.device, eventDescriptorTemplate)
return;
}
// 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]});
page.thingSelected.connect(function(device) {
selectedThings[eventDescriptorTemplate.selectionId] = device.id;
@ -59,6 +62,7 @@ Page {
// Fill in StateEvaluator
if (ruleTemplate.stateEvaluatorTemplate !== null) {
print("RuleFromTemplate: Filling stateEvaluator")
if (rule.stateEvaluator === null) {
var stateEvaluator = rule.createStateEvaluator();
rule.setStateEvaluator(stateEvaluator);
@ -73,6 +77,7 @@ 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)
if (ruleActionTemplate.selectionMode === RuleActionTemplate.SelectionModeInterface) {
// TODO: Implement blacklist for interface based actions
@ -92,19 +97,21 @@ Page {
// Did we pick a thing for this index before?
if (ruleActionTemplate.selectionId in selectedThings) {
var device = engine.deviceManager.devices.getDevice(selectedThings[ruleActionTemplate.selectionId]);
print("Already have a device for selectionId", ruleActionTemplate.selectionId, ":", device.name)
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) {
if (root.device && !deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(ruleActionTemplate.interfaceName) >= 0) {
print("Root device is matching and not used. Using for selectionId", ruleActionTemplate.selectionId, ":", root.device.name)
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")
// 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;
@ -142,7 +149,7 @@ Page {
}
// 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) {
if (root.device && !deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(ruleExitActionTemplate.interfaceName) >= 0) {
selectedThings[ruleExitActionTemplate.selectionId] = root.device.id;
createRuleAction(rule, ruleTemplate, rule.exitActions, root.device, ruleExitActionTemplate);
return;
@ -194,6 +201,7 @@ Page {
print("Rule complete!")
engine.ruleManager.addRule(rule);
rule.destroy();
print("emitting done")
root.done();
}
@ -224,7 +232,7 @@ Page {
fillRuleFromTemplate(rule, ruleTemplate);
return true;
}
if (!deviceIsUsed(root.device.id) && root.deviceClass.interfaces.indexOf(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName) >= 0 && stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName === ruleTemplate.interfaceName) {
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.valueOperator = stateEvaluatorTemplate.stateDescriptorTemplate.valueOperator;
@ -272,15 +280,20 @@ Page {
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)
var eventType = deviceClass.eventTypes.getEventType(eventDescriptor.eventTypeId);
for (var j = 0; j < eventType.paramTypes.count; j++) {
var paramType = eventType.paramTypes.get(j);
var paramDescriptorTemplate = eventDescriptorTemplate.paramDescriptors.getParamDescriptorByName(paramType.name)
// has the template a value for this? If so, set it, otherwise flag as needsParams
print("template:", paramType.id, eventDescriptorTemplate.paramDescriptors.count)
if (paramDescriptorTemplate && paramDescriptorTemplate.value !== undefined) {
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() {
@ -373,7 +386,7 @@ Page {
}
header: NymeaHeader {
text: qsTr("New magic")
text: root.device ? qsTr("New magic for %1").arg(root.device.name) : qsTr("New magic")
onBackPressed: root.done()
}
@ -382,14 +395,20 @@ Page {
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
model: RuleTemplatesFilterModel {
id: ruleTemplatesModel
ruleTemplates: RuleTemplates {}
filterInterfaceNames: root.deviceClass ? root.deviceClass.interfaces : []
filterByDevices: DevicesProxy {
engine: _engine
}
filterInterfaceNames: root.device ? root.device.deviceClass.interfaces : []
}
delegate: NymeaListItemDelegate {
width: parent.width
text: model.description
iconName: app.interfacesToIcon(model.interfaces)
onClicked: {
var ruleTemplate = ruleTemplatesModel.get(index);

View File

@ -58,6 +58,7 @@ MainPageTile {
if (model.name === "uncategorized") {
pageStack.push(Qt.resolvedUrl("../devicelistpages/" + page), {hiddenInterfaces: app.supportedInterfaces})
} else {
print("<entering for shown interfaces:", model.name)
pageStack.push(Qt.resolvedUrl("../devicelistpages/" + page), {shownInterfaces: [model.name]})
}
}