improve notifications view and rule action templates for it

This commit is contained in:
Michael Zanetti 2018-09-24 23:37:56 +02:00
parent d0825a5a34
commit f41f06537f
27 changed files with 820 additions and 192 deletions

View File

@ -127,9 +127,9 @@ QString AWSClient::username() const
return m_username;
}
QByteArray AWSClient::userId() const
QString AWSClient::userId() const
{
return m_identityId;
return m_userId;
}
AWSDevices *AWSClient::awsDevices() const

View File

@ -79,7 +79,7 @@ class AWSClient : public QObject
Q_PROPERTY(bool isLoggedIn READ isLoggedIn NOTIFY isLoggedInChanged)
Q_PROPERTY(QString username READ username NOTIFY isLoggedInChanged)
Q_PROPERTY(bool confirmationPending READ confirmationPending NOTIFY confirmationPendingChanged)
Q_PROPERTY(QByteArray userId READ userId NOTIFY isLoggedInChanged)
Q_PROPERTY(QString userId READ userId NOTIFY isLoggedInChanged)
Q_PROPERTY(QByteArray idToken READ idToken NOTIFY isLoggedInChanged)
Q_PROPERTY(AWSDevices* awsDevices READ awsDevices CONSTANT)
@ -100,7 +100,7 @@ public:
bool isLoggedIn() const;
QString username() const;
QByteArray userId() const;
QString userId() const;
AWSDevices* awsDevices() const;
bool confirmationPending() const;

View File

@ -5,7 +5,8 @@ EventDescriptorTemplate::EventDescriptorTemplate(const QString &interfaceName, c
m_interfaceName(interfaceName),
m_interfaceEvent(interfaceEvent),
m_selectionId(selectionId),
m_selectionMode(selectionMode)
m_selectionMode(selectionMode),
m_paramDescriptors(new ParamDescriptors(this))
{
}
@ -29,3 +30,8 @@ EventDescriptorTemplate::SelectionMode EventDescriptorTemplate::selectionMode()
{
return m_selectionMode;
}
ParamDescriptors *EventDescriptorTemplate::paramDescriptors() const
{
return m_paramDescriptors;
}

View File

@ -2,6 +2,7 @@
#define EVENTDESCRIPTORTEMPLATE_H
#include <QObject>
#include "types/paramdescriptors.h"
class EventDescriptorTemplate : public QObject
{
@ -10,6 +11,7 @@ class EventDescriptorTemplate : public QObject
Q_PROPERTY(QString interfaceEvent READ interfaceEvent CONSTANT)
Q_PROPERTY(int selectionId READ selectionId CONSTANT)
Q_PROPERTY(SelectionMode selectionMode READ selectionMode CONSTANT)
Q_PROPERTY(ParamDescriptors* paramDescriptors READ paramDescriptors CONSTANT)
public:
enum SelectionMode {
SelectionModeAny,
@ -24,12 +26,14 @@ public:
QString interfaceEvent() const;
int selectionId() const;
SelectionMode selectionMode() const;
ParamDescriptors* paramDescriptors() const;
private:
QString m_interfaceName;
QString m_interfaceEvent;
int m_selectionId = 0;
SelectionMode m_selectionMode = SelectionModeAny;
ParamDescriptors *m_paramDescriptors = nullptr;
};
#include <QAbstractListModel>

View File

@ -1,15 +1,15 @@
#include "ruleactiontemplate.h"
RuleActionTemplate::RuleActionTemplate(const QString &interfaceName, const QString &interfaceAction, int selectionId, SelectionMode selectionMode, QObject *parent):
RuleActionTemplate::RuleActionTemplate(const QString &interfaceName, const QString &interfaceAction, int selectionId, RuleActionTemplate::SelectionMode selectionMode, RuleActionParams *params, QObject *parent):
QObject(parent),
m_interfaceName(interfaceName),
m_interfaceAction(interfaceAction),
m_selectionId(selectionId),
m_selectionMode(selectionMode),
m_ruleActionParams(new RuleActionParams(this))
m_ruleActionParams(params ? params : new RuleActionParams())
{
m_ruleActionParams->setParent(this);
}
QString RuleActionTemplate::interfaceName() const

View File

@ -22,7 +22,7 @@ public:
};
Q_ENUM(SelectionMode)
explicit RuleActionTemplate(const QString &interfaceName, const QString &interfaceAction, int selectionId, SelectionMode selectionMode = SelectionModeAny, QObject *parent = nullptr);
explicit RuleActionTemplate(const QString &interfaceName, const QString &interfaceAction, int selectionId, SelectionMode selectionMode = SelectionModeAny, RuleActionParams *params = nullptr, QObject *parent = nullptr);
QString interfaceName() const;
QString interfaceAction() const;

View File

@ -3,8 +3,9 @@
#include "stateevaluatortemplate.h"
#include "ruleactiontemplate.h"
RuleTemplate::RuleTemplate(const QString &description, const QString &ruleNameTemplate, QObject *parent):
RuleTemplate::RuleTemplate(const QString &interfaceName, const QString &description, const QString &ruleNameTemplate, QObject *parent):
QObject(parent),
m_interfaceName(interfaceName),
m_description(description),
m_ruleNameTemplate(ruleNameTemplate),
m_eventDescriptorTemplates(new EventDescriptorTemplates(this)),
@ -13,6 +14,11 @@ RuleTemplate::RuleTemplate(const QString &description, const QString &ruleNameTe
{
}
QString RuleTemplate::interfaceName() const
{
return m_interfaceName;
}
QString RuleTemplate::description() const
{
return m_description;

View File

@ -10,6 +10,7 @@ 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(EventDescriptorTemplates* eventDescriptorTemplates READ eventDescriptorTemplates CONSTANT)
@ -18,8 +19,9 @@ class RuleTemplate : public QObject
Q_PROPERTY(RuleActionTemplates* ruleExitActionTemplates READ ruleExitActionTemplates CONSTANT)
public:
explicit RuleTemplate(const QString &description, const QString &ruleNameTemplate, QObject *parent = nullptr);
explicit RuleTemplate(const QString &interfaceName, const QString &description, const QString &ruleNameTemplate, QObject *parent = nullptr);
QString interfaceName() const;
QString description() const;
QString ruleNameTemplate() const;
@ -30,6 +32,7 @@ public:
RuleActionTemplates* ruleExitActionTemplates() const;
private:
QString m_interfaceName;
QString m_description;
QString m_ruleNameTemplate;
EventDescriptorTemplates* m_eventDescriptorTemplates = nullptr;

View File

@ -9,50 +9,121 @@
#include "types/ruleactionparams.h"
#include <QDebug>
#include <QDir>
#include <QJsonDocument>
#include <QMetaEnum>
RuleTemplates::RuleTemplates(QObject *parent) : QAbstractListModel(parent)
{
RuleTemplate* t;
EventDescriptorTemplate* evt;
ParamDescriptor* evpt;
StateEvaluatorTemplate* set;
RuleActionTemplate* rat;
RuleActionTemplate* reat; // exit
RuleActionParams* raps;
t = new RuleTemplate("Switch a light", "%0 switches %1", this);
evt = new EventDescriptorTemplate("button", "pressed", 0, EventDescriptorTemplate::SelectionModeDevice);
t->eventDescriptorTemplates()->addEventDescriptorTemplate(evt);
set = new StateEvaluatorTemplate(new StateDescriptorTemplate("light", "power", 1, StateDescriptorTemplate::ValueOperatorEquals, false));
t->setStateEvaluatorTemplate(set);
rat = new RuleActionTemplate("light", "power", 1, RuleActionTemplate::SelectionModeDevice);
rat->ruleActionParams()->setRuleActionParamByName("power", true);
t->ruleActionTemplates()->addRuleActionTemplate(rat);
reat = new RuleActionTemplate("light", "power", 1, RuleActionTemplate::SelectionModeDevice);
reat->ruleActionParams()->setRuleActionParamByName("power", false);
t->ruleExitActionTemplates()->addRuleActionTemplate(reat);
m_list.append(t);
QDir ruleTemplatesDir(":/ruletemplates");
t = new RuleTemplate("Intelligent blinds", "Intelligent blinds %1", this);
set = new StateEvaluatorTemplate(new StateDescriptorTemplate("temperaturesensor", "temperature", 0, StateDescriptorTemplate::ValueOperatorGreater, 20));
t->setStateEvaluatorTemplate(set);
rat = new RuleActionTemplate("simpleclosable", "close", 1, RuleActionTemplate::SelectionModeDevice);
t->ruleActionTemplates()->addRuleActionTemplate(rat);
reat = new RuleActionTemplate("simpleclosable", "open", 1, RuleActionTemplate::SelectionModeDevice);
t->ruleExitActionTemplates()->addRuleActionTemplate(reat);
m_list.append(t);
foreach (const QString &templateFile, ruleTemplatesDir.entryList({"*.json"})) {
qDebug() << "Loading rule template:" << ruleTemplatesDir.absoluteFilePath(templateFile);
QFile f(ruleTemplatesDir.absoluteFilePath(templateFile));
if (!f.open(QFile::ReadOnly)) {
qWarning() << "Cannot open rule template file for reading:" << ruleTemplatesDir.absoluteFilePath(templateFile);
continue;
}
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(f.readAll(), &error);
f.close();
if (error.error != QJsonParseError::NoError) {
qWarning() << "Error reading rule template json from file:" << ruleTemplatesDir.absoluteFilePath(templateFile) << error.offset << error.errorString();
continue;
}
foreach (const QVariant &ruleTemplateVariant, jsonDoc.toVariant().toMap().value("templates").toList()) {
QVariantMap ruleTemplate = ruleTemplateVariant.toMap();
t = new RuleTemplate("Leave home - This will turn of everything when you press a button.", "Leave home", this);
evt = new EventDescriptorTemplate("button", "pressed", 0, EventDescriptorTemplate::SelectionModeDevice);
t->eventDescriptorTemplates()->addEventDescriptorTemplate(evt);
rat = new RuleActionTemplate("power", "power", 1, RuleActionTemplate::SelectionModeInterface);
t->ruleActionTemplates()->addRuleActionTemplate(rat);
m_list.append(t);
// RuleTemplate base
t = new RuleTemplate(ruleTemplate.value("interfaceName").toString(), ruleTemplate.value("description").toString(), ruleTemplate.value("ruleNameTemplate").toString(), this);
// EventDescriptorTemplate
foreach (const QVariant &eventDescriptorVariant, ruleTemplate.value("eventDescriptorTemplates").toList()) {
QVariantMap eventDescriptorTemplate = eventDescriptorVariant.toMap();
evt = new EventDescriptorTemplate(
eventDescriptorTemplate.value("interfaceName").toString(),
eventDescriptorTemplate.value("interfaceEvent").toString(),
eventDescriptorTemplate.value("selectionId").toInt(),
EventDescriptorTemplate::SelectionModeDevice);
foreach (const QVariant &eventDescriptorParamVariant, eventDescriptorTemplate.value("params").toList()) {
QVariantMap eventDescriptorParamTemplate = eventDescriptorParamVariant.toMap();
evpt = new ParamDescriptor();
evpt->setParamName(eventDescriptorParamTemplate.value("name").toString());
if (eventDescriptorParamTemplate.contains("value")) {
evpt->setValue(eventDescriptorParamTemplate.value("value"));
}
evt->paramDescriptors()->addParamDescriptor(evpt);
}
t->eventDescriptorTemplates()->addEventDescriptorTemplate(evt);
}
t = new RuleTemplate("Remind me to water my plant", "Remind me to water my %0 plant", this);
evt = new EventDescriptorTemplate("humiditysensor", "humidity", 0, EventDescriptorTemplate::SelectionModeDevice);
t->eventDescriptorTemplates()->addEventDescriptorTemplate(evt);
m_list.append(t);
// StateEvaluatorTemplate
if (ruleTemplate.contains("stateEvaluatorTemplate")) {
QVariantMap stateEvaluatorTemplate = ruleTemplate.value("stateEvaluatorTemplate").toMap();
QVariantMap stateDescriptorTemplate = stateEvaluatorTemplate.value("stateDescriptorTemplate").toMap();
QMetaEnum selectionModeEnum = QMetaEnum::fromType<StateDescriptorTemplate::SelectionMode>();
QMetaEnum operatorEnum = QMetaEnum::fromType<StateDescriptorTemplate::ValueOperator>();
set = new StateEvaluatorTemplate(
new StateDescriptorTemplate(
stateDescriptorTemplate.value("interfaceName").toString(),
stateDescriptorTemplate.value("interfaceState").toString(),
stateDescriptorTemplate.value("selectionId").toInt(),
static_cast<StateDescriptorTemplate::SelectionMode>(selectionModeEnum.keyToValue(stateDescriptorTemplate.value("selectionMode", "SelectionModeAny").toByteArray().data())),
static_cast<StateDescriptorTemplate::ValueOperator>(operatorEnum.keyToValue(stateDescriptorTemplate.value("operator").toByteArray().data())),
stateDescriptorTemplate.value("value")));
t->setStateEvaluatorTemplate(set);
// TODO: Child evaluators not supported yet
}
// RuleActionTemplates
foreach (const QVariant &ruleActionVariant, ruleTemplate.value("ruleActionTemplates").toList()) {
QVariantMap ruleActionTemplate = ruleActionVariant.toMap();
raps = new RuleActionParams();
foreach (const QVariant &ruleActionParamVariant, ruleActionTemplate.value("params").toList()) {
QVariantMap ruleActionParamTemplate = ruleActionParamVariant.toMap();
raps->addRuleActionParam(new RuleActionParam(ruleActionParamTemplate.value("name").toString(), ruleActionParamTemplate.value("value")));
}
QMetaEnum selectionModeEnum = QMetaEnum::fromType<RuleActionTemplate::SelectionMode>();
rat = new RuleActionTemplate(
ruleActionTemplate.value("interfaceName").toString(),
ruleActionTemplate.value("interfaceAction").toString(),
ruleActionTemplate.value("selectionId").toInt(),
static_cast<RuleActionTemplate::SelectionMode>(selectionModeEnum.keyToValue(ruleActionTemplate.value("selectionMode", "SelectionModeDevice").toByteArray().data())),
raps);
t->ruleActionTemplates()->addRuleActionTemplate(rat);
}
// RuleExitActionTemplates
foreach (const QVariant &ruleActionVariant, ruleTemplate.value("ruleExitActionTemplates").toList()) {
QVariantMap ruleActionTemplate = ruleActionVariant.toMap();
raps = new RuleActionParams();
foreach (const QVariant &ruleActionParamVariant, ruleActionTemplate.value("params").toList()) {
QVariantMap ruleActionParamTemplate = ruleActionParamVariant.toMap();
raps->addRuleActionParam(new RuleActionParam(ruleActionParamTemplate.value("name").toString(), ruleActionParamTemplate.value("value")));
}
QMetaEnum selectionModeEnum = QMetaEnum::fromType<RuleActionTemplate::SelectionMode>();
rat = new RuleActionTemplate(
ruleActionTemplate.value("interfaceName").toString(),
ruleActionTemplate.value("interfaceAction").toString(),
ruleActionTemplate.value("selectionId").toInt(),
static_cast<RuleActionTemplate::SelectionMode>(selectionModeEnum.keyToValue(ruleActionTemplate.value("selectionMode", "SelectionModeDevice").toByteArray().data())),
raps);
t->ruleExitActionTemplates()->addRuleActionTemplate(rat);
}
qDebug() << "Added rule template:" << t->ruleActionTemplates()->rowCount();
m_list.append(t);
}
}
}
int RuleTemplates::rowCount(const QModelIndex &parent) const
@ -92,37 +163,40 @@ bool RuleTemplatesFilterModel::filterAcceptsRow(int source_row, const QModelInde
return false;
}
RuleTemplate *t = m_ruleTemplates->get(source_row);
qDebug() << "---------------" << t->description() << m_filterInterfaceNames;
qDebug() << "Checking interface" << t->description() << t->interfaceName() << "for usage with:" << m_filterInterfaceNames;
if (!m_filterInterfaceNames.isEmpty()) {
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) {
if (!m_filterInterfaceNames.contains(t->interfaceName())) {
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

@ -36,14 +36,15 @@ private:
class RuleTemplatesFilterModel: public QSortFilterProxyModel
{
Q_OBJECT
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)
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();}}
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();}
void setFilterInterfaceNames(const QStringList &filterInterfaceNames) { if (m_filterInterfaceNames != filterInterfaceNames) { m_filterInterfaceNames = filterInterfaceNames; emit filterInterfaceNamesChanged(); invalidateFilter(); emit countChanged(); }}
Q_INVOKABLE RuleTemplate* get(int index) {
if (index < 0 || index >= rowCount()) {
return nullptr;
@ -56,6 +57,7 @@ protected:
signals:
void ruleTemplatesChanged();
void filterInterfaceNamesChanged();
void countChanged();
private:
RuleTemplates* m_ruleTemplates = nullptr;
QStringList m_filterInterfaceNames;

View File

@ -1,10 +1,11 @@
#include "statedescriptortemplate.h"
StateDescriptorTemplate::StateDescriptorTemplate(const QString &interfaceName, const QString &interfaceState, int selectionId, StateDescriptorTemplate::ValueOperator valueOperator, const QVariant &value, QObject *parent):
StateDescriptorTemplate::StateDescriptorTemplate(const QString &interfaceName, const QString &interfaceState, int selectionId, StateDescriptorTemplate::SelectionMode selectionMode, StateDescriptorTemplate::ValueOperator valueOperator, const QVariant &value, QObject *parent):
QObject(parent),
m_interfaceName(interfaceName),
m_interfaceState(interfaceState),
m_selectionId(selectionId),
m_selectionMode(selectionMode),
m_valueOperator(valueOperator),
m_value(value)
{
@ -26,6 +27,11 @@ int StateDescriptorTemplate::selectionId() const
return m_selectionId;
}
StateDescriptorTemplate::SelectionMode StateDescriptorTemplate::selectionMode() const
{
return m_selectionMode;
}
StateDescriptorTemplate::ValueOperator StateDescriptorTemplate::valueOperator() const
{
return m_valueOperator;

View File

@ -10,10 +10,17 @@ class StateDescriptorTemplate : public QObject
Q_PROPERTY(QString interfaceName READ interfaceName CONSTANT)
Q_PROPERTY(QString interfaceState READ interfaceState CONSTANT)
Q_PROPERTY(int selectionId READ selectionId CONSTANT)
Q_PROPERTY(SelectionMode selectionMode READ selectionMode CONSTANT)
Q_PROPERTY(ValueOperator valueOperator READ valueOperator CONSTANT)
Q_PROPERTY(QVariant value READ value CONSTANT)
public:
enum SelectionMode {
SelectionModeAny,
SelectionModeDevice,
SelectionModeInterface,
};
Q_ENUM(SelectionMode)
enum ValueOperator {
ValueOperatorEquals,
ValueOperatorNotEquals,
@ -24,20 +31,22 @@ public:
};
Q_ENUM(ValueOperator)
explicit StateDescriptorTemplate(const QString &interfaceName, const QString &interfaceState, int selectionId, ValueOperator valueOperator = ValueOperatorEquals, const QVariant &value = QVariant(), QObject *parent = nullptr);
explicit StateDescriptorTemplate(const QString &interfaceName, const QString &interfaceState, int selectionId, SelectionMode selectionMode, ValueOperator valueOperator = ValueOperatorEquals, const QVariant &value = QVariant(), QObject *parent = nullptr);
QString interfaceName() const;
QString interfaceState() const;
int selectionId() const;
SelectionMode selectionMode() const;
ValueOperator valueOperator() const;
QVariant value() const;
private:
QString m_interfaceName;
QString m_interfaceState;
int m_selectionId = 0;
SelectionMode m_selectionMode = SelectionModeAny;
ValueOperator m_valueOperator = ValueOperatorEquals;
QVariant m_value;
int m_selectionId = 0;
};
#endif // STATEDESCRIPTORTEMPLATE_H

View File

@ -34,7 +34,7 @@ class Param : public QObject
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
public:
Param(const QString &paramTypeId = QString(), const QVariant &value = QVariant(), QObject *parent = 0);
Param(const QString &paramTypeId = QString(), const QVariant &value = QVariant(), QObject *parent = nullptr);
Param(QObject *parent);
QString paramTypeId() const;

View File

@ -1,5 +1,12 @@
#include "ruleactionparam.h"
RuleActionParam::RuleActionParam(const QString &paramName, const QVariant &value, QObject *parent):
Param(parent),
m_paramName(paramName)
{
setValue(value);
}
RuleActionParam::RuleActionParam(QObject *parent) : Param(parent)
{

View File

@ -14,6 +14,7 @@ class RuleActionParam : public Param
Q_PROPERTY(QString eventTypeId READ eventTypeId WRITE setEventTypeId NOTIFY eventTypeIdChanged)
Q_PROPERTY(QString eventParamTypeId READ eventParamTypeId WRITE setEventParamTypeId NOTIFY eventParamTypeIdChanged)
public:
explicit RuleActionParam(const QString &paramName, const QVariant &value, QObject *parent = nullptr);
explicit RuleActionParam(QObject *parent = nullptr);
QString paramName() const;

View File

@ -30,7 +30,8 @@ SOURCES += main.cpp \
OTHER_FILES += $$files(*.qml, true)
RESOURCES += resources.qrc
RESOURCES += resources.qrc \
ruletemplates.qrc
equals(STYLES_PATH, "") {
RESOURCES += styles.qrc
} else {
@ -121,4 +122,7 @@ target.path = /usr/bin
INSTALLS += target
DISTFILES += \
ui/components/BusyOverlay.qml
ui/components/BusyOverlay.qml \
ui/devicepages/NotificationsDevicePage.qml \
ruletemplates/buttontemplates.json \
ruletemplates/notificationtemplates.json

View File

@ -248,5 +248,6 @@
<file>ui/appsettings/AppSettingsPage.qml</file>
<file>ui/appsettings/DeveloperOptionsPage.qml</file>
<file>ui/appsettings/CloudLoginPage.qml</file>
<file>ui/devicepages/NotificationsDevicePage.qml</file>
</qresource>
</RCC>

View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>ruletemplates/buttontemplates.json</file>
<file>ruletemplates/notificationtemplates.json</file>
</qresource>
</RCC>

View File

@ -0,0 +1,169 @@
{
"templates": [
{
"interfaceName": "simplemultibutton",
"description": "Switch a light",
"ruleNameTemplate": "%0 switches %1",
"eventDescriptorTemplates": [
{
"interfaceName": "simplemultibutton",
"interfaceEvent": "pressed",
"selectionId": 0,
"params": [
{
"name": "buttonName"
}
]
}
],
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "light",
"interfaceState": "power",
"operator": "ValueOperatorEquals",
"value": false,
"selectionId": 1,
"selectionMode": "SelectionModeDevice"
}
},
"ruleActionTemplates": [
{
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"selectionMode": "SelectionModeDevice",
"params": [
{
"name": "power",
"value": true
}
]
}
],
"ruleExitActionTemplates": [
{
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"selectionMode": "SelectionModeDevice",
"params": [
{
"name": "power",
"value": false
}
]
}
]
},
{
"interfaceName": "simplebutton",
"description": "Switch a light",
"ruleNameTemplate": "%0 switches %1",
"eventDescriptorTemplates": [
{
"interfaceName": "simplebutton",
"interfaceEvent": "pressed",
"selectionId": 0
}
],
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "light",
"interfaceState": "power",
"operator": "ValueOperatorEquals",
"value": false,
"selectionId": 1,
"selectionMode": "SelectionModeDevice"
}
},
"ruleActionTemplates": [
{
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"selectionMode": "SelectionModeDevice",
"params": [
{
"name": "power",
"value": true
}
]
}
],
"ruleExitActionTemplates": [
{
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"selectionMode": "SelectionModeDevice",
"params": [
{
"name": "power",
"value": false
}
]
}
]
},
{
"interfaceName": "simplemultibutton",
"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",
"interfaceEvent": "pressed",
"selectionId": 0,
"selectionMode": "SelectionModeDevice"
}
],
"ruleActionTemplates": [
{
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"selectionMode": "SelectionModeInterface",
"params": [
{
"name": "power",
"value": false
}
]
}
]
}
]
}

View File

@ -0,0 +1,97 @@
{
"templates": [
{
"interfaceName": "notifications",
"description": "Notify me when a device runs out of battery",
"ruleNameTemplate": "Low battery alert for %0",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "battery",
"interfaceState": "batteryCritical",
"operator": "ValueOperatorEquals",
"value": true,
"selectionId": 0
}
},
"ruleActionTemplates": [
{
"interfaceName": "notifications",
"interfaceAction": "notify",
"selectionId": 1,
"params": [
{
"name": "title",
"value": "Low battery alert"
},
{
"name": "body",
"value": "%0 runs out of battery"
}
]
}
]
},
{
"interfaceName": "notifications",
"description": "Notify me when a thing gets disconnected",
"ruleNameTemplate": "Disconnect alert for %0",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "connectable",
"interfaceState": "connected",
"selectionId": 0,
"operator": "ValueOperatorEquals",
"value": false
}
},
"ruleActionTemplates": [
{
"interfaceName": "notifications",
"interfaceAction": "notify",
"selectionId": 1,
"params": [
{
"name": "title",
"value": "Disconnect alert"
},
{
"name": "body",
"value": "%0 has disconnected"
}
]
}
]
},
{
"interfaceName": "notifications",
"description": "Notify me when a thing connects",
"ruleNameTemplate": "Connection notification for %0",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "connectable",
"interfaceState": "connected",
"selectionId": 0,
"operator": "ValueOperatorEquals",
"value": true
}
},
"ruleActionTemplates": [
{
"interfaceName": "notifications",
"interfaceAction": "notify",
"selectionId": 1,
"params": [
{
"name": "title",
"value": "Thin connected"
},
{
"name": "body",
"value": "%0 has connected"
}
]
}
]
}
]
}

View File

@ -6,8 +6,6 @@ import Qt.labs.settings 1.0
import QtQuick.Window 2.3
import Nymea 1.0
//import QtFirebase 1.0
ApplicationWindow {
id: app
visible: true
@ -347,6 +345,12 @@ ApplicationWindow {
return "button";
case "sensor":
return qsTr("sensor")
case "battery":
return qsTr("battery powered thing")
case "connectable":
return qsTr("connectable thing")
default:
console.warn("Unhandled interfaceToDisplayName:", name)
}
}
@ -370,6 +374,8 @@ ApplicationWindow {
page = "ShutterDevicePage.qml";
} else if (interfaceList.indexOf("extendedawning") >= 0) {
page = "AwningDevicePage.qml";
} else if (interfaceList.indexOf("notifications") >= 0) {
page = "NotificationsDevicePage.qml";
} else {
page = "GenericDevicePage.qml";
}

View File

@ -13,6 +13,8 @@ Item {
property var logsModel: null
property alias delegate: listView.delegate
ColumnLayout {
anchors.fill: parent

View File

@ -0,0 +1,149 @@
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
import "../components"
import "../customviews"
DevicePageBase {
id: root
property bool inputVisible: false
ColumnLayout {
anchors.fill: parent
Item {
Layout.fillWidth: true
Layout.preferredHeight: root.inputVisible ? inputColumn.implicitHeight : 0
Behavior on Layout.preferredHeight { NumberAnimation { duration: 130; easing.type: Easing.InOutQuad } }
ColumnLayout {
id: inputColumn
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
TextField {
id: titleTextField
Layout.fillWidth: true
Layout.topMargin: app.margins
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
placeholderText: qsTr("Title")
}
TextArea {
id: bodyTextField
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
placeholderText: qsTr("Text")
wrapMode: Text.WordWrap
}
}
}
Button {
Layout.fillWidth: true
Layout.margins: app.margins
text: !root.inputVisible ?
qsTr("Send a notification")
: titleTextField.displayText.length > 0 ?
qsTr("Send now")
: qsTr("Cancel")
onClicked: {
if (root.inputVisible && titleTextField.displayText.length > 0) {
var actionType = root.deviceClass.actionTypes.findByName("notify")
var params = []
var titleParam = {}
titleParam["paramTypeId"] = actionType.paramTypes.findByName("title").id
titleParam["value"] = titleTextField.displayText
params.push(titleParam)
var bodyParam = {}
bodyParam["paramTypeId"] = actionType.paramTypes.findByName("body").id
bodyParam["value"] = bodyTextField.text
params.push(bodyParam)
Engine.deviceManager.executeAction(root.device.id, actionType.id, params)
}
root.inputVisible = !root.inputVisible
}
}
ThinDivider {}
GenericTypeLogView {
Layout.fillHeight: true
Layout.fillWidth: true
text: qsTr("%1 notifications sent to this device in the last 24 hours.")
logsModel: LogsModel {
deviceId: root.device.id
live: true
Component.onCompleted: update()
typeIds: [root.deviceClass.actionTypes.findByName("notify").id];
}
delegate: MeaListItemDelegate {
width: parent.width
iconName: "../images/notification.svg"
text: model.value.trim()
subText: Qt.formatDateTime(model.timestamp)
progressive: false
onClicked: {
print("a", model.value.trim())
var parts = model.value.trim().split(', ')
print("b", parts)
var popup = detailsPopup.createObject(root, {timestamp: model.timestamp, notificationTitle: parts[1], notificationBody: parts[0]});
popup.open();
}
}
}
}
Component {
id: detailsPopup
MeaDialog {
id: detailsDialog
property string timestamp
property string notificationTitle
property string notificationBody
title: qsTr("Notification details")
Label {
Layout.fillWidth: true
text: qsTr("Date sent")
font.bold: true
}
Label {
Layout.fillWidth: true
text: Qt.formatDateTime(detailsDialog.timestamp)
}
Label {
Layout.topMargin: app.margins
Layout.fillWidth: true
text: qsTr("Title")
font.bold: true
}
Label {
Layout.fillWidth: true
text: detailsDialog.notificationTitle
wrapMode: Text.WordWrap
}
Label {
Layout.topMargin: app.margins
Layout.fillWidth: true
text: qsTr("Text")
font.bold: true
}
Label {
Layout.fillWidth: true
text: detailsDialog.notificationBody
wrapMode: Text.WordWrap
}
}
}
}

View File

@ -23,20 +23,31 @@ Page {
}
}
RuleTemplatesFilterModel {
id: ruleTemplatesModel
ruleTemplates: RuleTemplates {}
readonly property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(root.device.deviceClassId) : null
filterInterfaceNames: deviceClass ? deviceClass.interfaces : []
}
// Rule is optional and might be initialized with anything wanted. A new, empty one will be created if null
// This Page will take ownership of the rule and delete it eventually.
function addRule(rule) {
if (rule === null || rule === undefined) {
d.editRulePage = pageStack.push(Qt.resolvedUrl("NewThingMagicPage.qml"), {device: root.device});
d.editRulePage.manualCreation.connect(function() {
pageStack.pop();
rule = Engine.ruleManager.createNewRule();
addRule(rule)
})
d.editRulePage.done.connect(function() {pageStack.pop(root);});
return;
print("creating new rule. have", ruleTemplatesModel.count, "templates", ruleTemplatesModel.deviceClass.interfaces)
if (ruleTemplatesModel.count > 0) {
d.editRulePage = pageStack.push(Qt.resolvedUrl("NewThingMagicPage.qml"), {device: root.device});
d.editRulePage.manualCreation.connect(function() {
pageStack.pop();
rule = Engine.ruleManager.createNewRule();
addRule(rule)
})
d.editRulePage.done.connect(function() {pageStack.pop(root);});
return;
}
rule = Engine.ruleManager.createNewRule();
}
d.editRulePage = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rule});
d.editRulePage = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rule, initialDeviceToBeAdded: root.device});
d.editRulePage.StackView.onRemoved.connect(function() {
rule.destroy();
})
@ -48,11 +59,11 @@ Page {
pageStack.pop();
})
// if (rule.eventDescriptors.count === 0) {
// var eventDescriptor = rule.eventDescriptors.createNewEventDescriptor();
// eventDescriptor.deviceId = device.id;
// page.selectEventDescriptorData(eventDescriptor);
// }
// if (rule.eventDescriptors.count === 0) {
// var eventDescriptor = rule.eventDescriptors.createNewEventDescriptor();
// eventDescriptor.deviceId = device.id;
// page.selectEventDescriptorData(eventDescriptor);
// }
}

View File

@ -8,6 +8,8 @@ Page {
id: root
property var rule: null
property var initialDeviceToBeAdded: null
property bool busy: false
readonly property bool isEventBased: rule.eventDescriptors.count > 0 || rule.timeDescriptor.timeEventItems.count > 0
@ -128,9 +130,7 @@ Page {
})
statePage.done.connect(function() {
root.rule.setStateEvaluator(stateEvaluator)
pageStack.pop();
pageStack.pop();
pageStack.pop();
pageStack.pop(root);
})
}
@ -437,7 +437,12 @@ Page {
text: eventsRepeater.count == 0 && timeEventRepeater.count === 0 ? qsTr("Configure...") : qsTr("Add another...")
visible: !root.isStateBased
onClicked: {
if (root.rule.timeDescriptor.calendarItems.count > 0) {
if (root.initialDeviceToBeAdded !== null) {
var eventDescriptor = root.rule.eventDescriptors.createNewEventDescriptor();
eventDescriptor.deviceId = root.initialDeviceToBeAdded.id;
root.initialDeviceToBeAdded = null;
selectEventDescriptorData(eventDescriptor);
} else if (root.rule.timeDescriptor.calendarItems.count > 0) {
root.addEventDescriptor()
} else {
pageStack.push(eventQuestionPageComponent)
@ -526,7 +531,12 @@ Page {
qsTr("Add another...")
visible: root.rule.timeDescriptor.timeEventItems.count === 0 || root.rule.stateEvaluator === null
onClicked: {
if (root.rule.timeDescriptor.timeEventItems.count > 0) {
if (root.initialDeviceToBeAdded !== null) {
var stateEvaluator = root.rule.createStateEvaluator();
stateEvaluator.stateDescriptor.deviceId = root.initialDeviceToBeAdded.id
root.initialDeviceToBeAdded = null;
selectStateDescriptorData(stateEvaluator)
} else if (root.rule.timeDescriptor.timeEventItems.count > 0) {
root.rule.setStateEvaluator(root.rule.createStateEvaluator());
} else if (root.rule.stateEvaluator !== null) {
root.addCalendarItem();
@ -578,11 +588,18 @@ Page {
Layout.margins: app.margins
text: root.isEmpty ? qsTr("Configure...") :
actionsRepeater.count == 0 ? qsTr("Add an action...") : qsTr("Add another action...")
onClicked: {
onClicked: {
if (root.isEmpty) {
root.rule.executable = true;
}
var page = pageStack.push(ruleActionQuestionPageComponent, {exitAction: false});
if (root.initialDeviceToBeAdded !== null) {
var ruleAction = root.rule.actions.createNewRuleAction();
ruleAction.deviceId = root.initialDeviceToBeAdded.id;
root.initialDeviceToBeAdded = null;
selectRuleActionData(root.rule.actions, ruleAction)
} else {
var page = pageStack.push(ruleActionQuestionPageComponent, {exitAction: false});
}
}
visible: root.actionsVisible
}

View File

@ -22,37 +22,25 @@ 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)
// 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]);
var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
var eventDescriptor = rule.eventDescriptors.createNewEventDescriptor();
eventDescriptor.deviceId = device.id
eventDescriptor.eventTypeId = deviceClass.eventTypes.findByName(eventDescriptorTemplate.interfaceEvent).id
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
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) {
var eventDescriptor = rule.eventDescriptors.createNewEventDescriptor();
eventDescriptor.deviceId = root.device.id;
eventDescriptor.eventTypeId = root.deviceClass.eventTypes.findByName(eventDescriptorTemplate.interfaceEvent).id
rule.eventDescriptors.addEventDescriptor(eventDescriptor);
if (selectedThings.indexOf(root.device.id) === -1 && root.deviceClass.interfaces.indexOf(eventDescriptorTemplate.interfaceName) >= 0 && eventDescriptorTemplate.interfaceName === ruleTemplate.interfaceName) {
selectedThings.push(root.device.id);
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
createEventDescriptor(rule, ruleTemplate, selectedThings, root.device, eventDescriptorTemplate)
return;
}
// We need to pick a thing
var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [eventDescriptorTemplate.interfaceName]});
page.thingSelected.connect(function(device) {
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;
rule.eventDescriptors.addEventDescriptor(eventDescriptor);
selectedThings.push(device.id);
fullRuleFromTemplate(rule, ruleTemplate, selectedThings);
createEventDescriptor(rule, ruleTemplate, selectedThings, device, eventDescriptorTemplate)
return;
})
page.backPressed.connect(function() {rule.destroy(); root.done();})
@ -76,58 +64,42 @@ Page {
for (var i = rule.actions.count; i < ruleTemplate.ruleActionTemplates.count; i++) {
var ruleActionTemplate = ruleTemplate.ruleActionTemplates.get(i);
// Did we pick a thing for this index before?
if (selectedThings.length > ruleActionTemplate.selectionId) {
if (ruleActionTemplate.selectionMode === RuleActionTemplate.SelectionModeInterface) {
// TODO: Implement blacklist for interface based actions
var ruleAction = rule.actions.createNewRuleAction();
var deviceId = selectedThings[ruleActionTemplate.selectionId];
var device = Engine.deviceManager.devices.getDevice(deviceId);
var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
ruleAction.deviceId = deviceId;
ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleActionTemplate.interfaceAction).id
ruleAction.interfaceName = ruleActionTemplate.interfaceName;
ruleAction.interfaceAction = ruleActionTemplate.interfaceAction;
for (var j = 0; j < ruleActionTemplate.ruleActionParams.count; j++) {
var ruleActionParam = ruleActionTemplate.ruleActionParams.get(j)
var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId);
var paramType = actionType.paramTypes.findByName(ruleActionParam.paramName);
ruleAction.ruleActionParams.setRuleActionParam(paramType.id, ruleActionParam.value)
ruleAction.ruleActionParams.setRuleActionParamByName(ruleActionParam.paramName, ruleActionParam.value)
}
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) {
var ruleAction = rule.actions.createNewRuleAction();
ruleAction.deviceId = root.device.id;
ruleAction.actionTypeId = root.deviceClass.actionTypes.findByName(ruleActionTemplate.interfaceAction).id
for (var j = 0; j < ruleActionTemplate.ruleActionParams.count; j++) {
var ruleActionParam = ruleActionTemplate.ruleActionParams.get(j)
var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId);
var paramType = actionType.paramTypes.findByName(ruleActionParam.paramName);
ruleAction.ruleActionParams.setRuleActionParam(paramType.id, ruleActionParam.value)
}
rule.actions.addRuleAction(ruleAction);
if (selectedThings.indexOf(root.device.id) === -1 && root.deviceClass.interfaces.indexOf(ruleActionTemplate.interfaceName) >= 0 && ruleActionTemplate.interfaceName === ruleTemplate.interfaceName) {
selectedThings.push(root.device.id);
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
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) {
var ruleAction = rule.actions.createNewRuleAction();
ruleAction.deviceId = device.id;
var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleActionTemplate.interfaceAction).id;
for (var j = 0; j < ruleActionTemplate.ruleActionParams.count; j++) {
var ruleActionParam = ruleActionTemplate.ruleActionParams.get(j)
var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId);
var paramType = actionType.paramTypes.findByName(ruleActionParam.paramName);
ruleAction.ruleActionParams.setRuleActionParam(paramType.id, ruleActionParam.value)
}
rule.actions.addRuleAction(ruleAction);
print("selected device", device.name)
print("template is", ruleActionTemplate.interfaceName)
selectedThings.push(device.id);
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
createRuleAction(rule, ruleTemplate, selectedThings, rule.actions, device, ruleActionTemplate)
return;
})
page.backPressed.connect(function() {rule.destroy(); root.done();})
@ -138,58 +110,39 @@ Page {
for (var i = rule.exitActions.count; i < ruleTemplate.ruleExitActionTemplates.count; i++) {
var ruleExitActionTemplate = ruleTemplate.ruleExitActionTemplates.get(i);
// Did we pick a thing for this index before?
if (selectedThings.length > ruleExitActionTemplate.selectionId) {
var ruleAction = rule.exitActions.createNewRuleAction();
var deviceId = selectedThings[ruleExitActionTemplate.selectionId];
var device = Engine.deviceManager.devices.getDevice(deviceId);
var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
ruleAction.deviceId = deviceId;
ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleExitActionTemplate.interfaceAction).id
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.ruleActionParams.count; j++) {
var ruleActionParam = ruleExitActionTemplate.ruleActionParams.get(j)
var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId);
var paramType = actionType.paramTypes.findByName(ruleActionParam.paramName);
ruleAction.ruleActionParams.setRuleActionParam(paramType.id, ruleActionParam.value)
ruleExitAction.ruleActionParams.setRuleActionParam(ruleActionParam.paramName, ruleActionParam.value)
}
rule.exitActions.addRuleAction(ruleAction);
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
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);
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) {
var ruleAction = rule.exitActions.createNewRuleAction();
ruleAction.deviceId = root.device.id;
ruleAction.actionTypeId = root.deviceClass.actionTypes.findByName(ruleExitActionTemplate.interfaceAction).id
for (var j = 0; j < ruleExitActionTemplate.ruleActionParams.count; j++) {
var ruleActionParam = ruleExitActionTemplate.ruleActionParams.get(j)
var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId);
var paramType = actionType.paramTypes.findByName(ruleActionParam.paramName);
ruleAction.ruleActionParams.setRuleActionParam(paramType.id, ruleActionParam.value)
}
rule.exitActions.addRuleAction(ruleAction);
if (selectedThings.indexOf(root.device.id) === -1 && root.deviceClass.interfaces.indexOf(ruleExitActionTemplate.interfaceName) >= 0 && ruleExitActionTemplate.interfaceName === ruleTemplate.interfaceName) {
selectedThings.push(root.device.id);
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
createRuleAction(rule, ruleTemplate, selectedThings, 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) {
var ruleAction = rule.exitActions.createNewRuleAction();
ruleAction.deviceId = device.id;
var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleExitActionTemplate.interfaceAction).id;
for (var j = 0; j < ruleExitActionTemplate.ruleActionParams.count; j++) {
var ruleActionParam = ruleExitActionTemplate.ruleActionParams.get(j)
var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId);
var paramType = actionType.paramTypes.findByName(ruleActionParam.paramName);
ruleAction.ruleActionParams.setRuleActionParam(paramType.id, ruleActionParam.value)
}
rule.exitActions.addRuleAction(ruleAction);
selectedThings.push(device.id);
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
createRuleAction(rule, ruleTemplate, selectedThings, rule.exitActions, device, ruleExitActionTemplate);
return;
})
page.backPressed.connect(function() {rule.destroy(); root.done();})
@ -197,10 +150,31 @@ Page {
}
// 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.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);
}
}
}
}
print("Rule complete!")
@ -210,8 +184,19 @@ Page {
}
function fillStateEvaluatorFromTemplate(rule, ruleTemplate, stateEvaluator, stateEvaluatorTemplate, selectedThings) {
if (stateEvaluatorTemplate.stateDescriptorTemplate !== null && selectedThings.indexOf(stateEvaluator.stateDescriptor.deviceId) === -1) {
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]
@ -224,7 +209,7 @@ Page {
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
return true;
}
if (selectedThings.indexOf(root.device.id) === -1 && root.deviceClass.interfaces.indexOf(stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName) >= 0) {
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;
@ -233,7 +218,9 @@ Page {
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
return true;
}
var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"), {shownInterfaces: [stateEvaluatorTemplate.stateDescriptorTemplate.interfaceName]});
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;
@ -243,6 +230,13 @@ Page {
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;
}
@ -256,6 +250,47 @@ Page {
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) {
eventDescriptor.paramDescriptors.addParamDescriptor(paramDescriptorTemplate.paramName, paramDescriptorTemplate.value);
} 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);
})
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.ruleActionParams.count; j++) {
var ruleActionParam = ruleActionTemplate.ruleActionParams.get(j)
var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId);
var paramType = actionType.paramTypes.findByName(ruleActionParam.paramName);
ruleAction.ruleActionParams.setRuleActionParam(paramType.id, ruleActionParam.value)
}
ruleActions.addRuleAction(ruleAction);
fillRuleFromTemplate(rule, ruleTemplate, selectedThings);
}
header: GuhHeader {
text: qsTr("New magic")
onBackPressed: root.done()

View File

@ -9,13 +9,16 @@ Page {
id: root
property bool selectInterface: false
signal backPressed();
signal thingSelected(var device);
signal interfaceSelected(string interfaceName);
property alias showEvents: interfacesProxy.showEvents
property alias showActions: interfacesProxy.showActions
property alias showStates: interfacesProxy.showStates
property alias shownInterfaces: devicesProxy.shownInterfaces
property bool allowSelectAny: false
signal backPressed();
signal thingSelected(var device);
signal interfaceSelected(string interfaceName);
signal anySelected();
header: GuhHeader {
text: root.selectInterface ?
@ -37,6 +40,16 @@ Page {
ColumnLayout {
anchors.fill: parent
MeaListItemDelegate {
Layout.fillWidth: true
text: qsTr("Any %1").arg(app.interfaceToDisplayName(root.shownInterfaces[0]))
visible: root.allowSelectAny
onClicked: {
root.anySelected();
}
}
ThinDivider { visible: root.allowSelectAny }
ListView {
Layout.fillWidth: true
Layout.fillHeight: true