Merge PR #234: Improve rule creation

This commit is contained in:
Jenkins 2019-09-01 01:51:45 +02:00
commit 63cb1b4ced
53 changed files with 1760 additions and 290 deletions

View File

@ -69,7 +69,7 @@ void ZeroconfDiscovery::serviceEntryAdded(const QZeroConfService &entry)
return;
}
qDebug() << "zeroconf service discovered" << entry->type() << entry->name() << " IP:" << entry->ip().toString() << entry->txt();
// qDebug() << "zeroconf service discovered" << entry->type() << entry->name() << " IP:" << entry->ip().toString() << entry->txt();
QString uuid;
bool sslEnabled = false;
@ -97,7 +97,7 @@ void ZeroconfDiscovery::serviceEntryAdded(const QZeroConfService &entry)
if (!host) {
host = new NymeaHost(m_nymeaHosts);
host->setUuid(uuid);
qDebug() << "ZeroConf: Adding new host:" << serverName << uuid;
// qDebug() << "ZeroConf: Adding new host:" << serverName << uuid;
m_nymeaHosts->addHost(host);
}
host->setName(serverName);
@ -113,14 +113,14 @@ void ZeroconfDiscovery::serviceEntryAdded(const QZeroConfService &entry)
url.setPort(entry->port());
Connection *connection = host->connections()->find(url);
if (!connection) {
qDebug() << "Zeroconf: Adding new connection to host:" << host->name() << url.toString();
// qDebug() << "Zeroconf: Adding new connection to host:" << host->name() << url.toString();
QString displayName = QString("%1:%2").arg(url.host()).arg(url.port());
Connection::BearerType bearerType = QHostAddress(url.host()).isLoopback() ? Connection::BearerTypeLoopback : Connection::BearerTypeLan;
connection = new Connection(url, bearerType, sslEnabled, displayName);
connection->setOnline(true);
host->connections()->addConnection(connection);
} else {
qDebug() << "Zeroconf: Setting connection online:" << host->name() << url.toString();
// qDebug() << "Zeroconf: Setting connection online:" << host->name() << url.toString();
connection->setOnline(true);
}
}

View File

@ -412,11 +412,11 @@ void NymeaConnection::updateActiveBearers()
}
if (m_availableBearerTypes != availableBearerTypes) {
qDebug() << "Available Bearer Types changed:" << availableBearerTypes;
// qDebug() << "Available Bearer Types changed:" << availableBearerTypes;
m_availableBearerTypes = availableBearerTypes;
emit availableBearerTypesChanged();
} else {
qDebug() << "Available Bearer Types:" << availableBearerTypes;
// qDebug() << "Available Bearer Types:" << availableBearerTypes;
}
if (!m_currentHost) {

View File

@ -34,6 +34,22 @@ DeviceManager::DeviceManager(JsonRpcClient* jsonclient, QObject *parent) :
m_jsonClient(jsonclient)
{
m_jsonClient->registerNotificationHandler(this, "notificationReceived");
EventHandler *eventHandler = new EventHandler(this);
m_jsonClient->registerNotificationHandler(eventHandler, "notificationReceived");
connect(eventHandler, &EventHandler::eventReceived, this, [this](const QVariantMap event) {
QUuid deviceId = event.value("deviceId").toUuid();
QUuid eventTypeId = event.value("eventTypeId").toUuid();
Device *dev = m_devices->getDevice(deviceId);
if (!dev) {
qWarning() << "received an event from a device we don't know..." << deviceId << event;
return;
}
// 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());
});
}
void DeviceManager::clear()

View File

@ -120,6 +120,8 @@ signals:
void fetchingDataChanged();
void notificationReceived(const QString &deviceId, const QString &eventTypeId, const QVariantList &params);
void eventTriggered(const QString &deviceId, const QString &eventTypeId, const QVariantMap params);
private:
Vendors *m_vendors;
Plugins *m_plugins;
@ -135,6 +137,28 @@ private:
QHash<int, QPointer<BrowserItems> > m_browsingRequests;
QHash<int, QPointer<BrowserItem> > m_browserDetailsRequests;
};
// TODO: Kinda shitty that Device Events are not sent from the Devices namespace...
class EventHandler: public JsonHandler {
Q_OBJECT
public:
EventHandler(QObject *parent = nullptr): JsonHandler(parent) {}
QString nameSpace() const override {
return "Events";
}
signals:
void eventReceived(const QVariantMap &event);
private:
Q_INVOKABLE void notificationReceived(const QVariantMap &data) {
emit eventReceived(data.value("params").toMap().value("event").toMap());
}
};
#endif // DEVICEMANAGER_H

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

@ -28,7 +28,7 @@ class JsonHandler : public QObject
{
Q_OBJECT
public:
JsonHandler(QObject *parent = 0);
JsonHandler(QObject *parent = nullptr);
virtual QString nameSpace() const = 0;
};

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,11 +8,13 @@
#include "types/ruleactionparam.h"
#include "types/ruleactionparams.h"
#include "devicesproxy.h"
#include <QDebug>
#include <QDir>
#include <QJsonDocument>
#include <QMetaEnum>
#include <QCoreApplication>
RuleTemplates::RuleTemplates(QObject *parent) : QAbstractListModel(parent)
{
@ -20,10 +22,7 @@ RuleTemplates::RuleTemplates(QObject *parent) : QAbstractListModel(parent)
RuleTemplate* t;
EventDescriptorTemplate* evt;
ParamDescriptor* evpt;
StateEvaluatorTemplate* set;
RuleActionTemplate* rat;
RuleActionTemplate* reat; // exit
RuleActionParamTemplate* rapt;
RuleActionParamTemplates* rapts;
QDir ruleTemplatesDir(":/ruletemplates");
@ -46,7 +45,13 @@ RuleTemplates::RuleTemplates(QObject *parent) : QAbstractListModel(parent)
QVariantMap ruleTemplate = ruleTemplateVariant.toMap();
// RuleTemplate base
t = new RuleTemplate(ruleTemplate.value("interfaceName").toString(), ruleTemplate.value("description").toString(), ruleTemplate.value("ruleNameTemplate").toString(), this);
QString descriptionContext = QString("description for %0").arg(QFileInfo(templateFile).baseName());
QString nameTemplateContext = QString("ruleNameTemplate for %0").arg(QFileInfo(templateFile).baseName());
t = new RuleTemplate(ruleTemplate.value("interfaceName").toString(),
qApp->translate(descriptionContext.toUtf8(), ruleTemplate.value("description").toByteArray()),
qApp->translate(nameTemplateContext.toUtf8(), ruleTemplate.value("ruleNameTemplate").toByteArray()),
this);
qDebug() << "Loading rule template" << ruleTemplate.value("description").toString() << tr(ruleTemplate.value("description").toByteArray());
// EventDescriptorTemplate
foreach (const QVariant &eventDescriptorVariant, ruleTemplate.value("eventDescriptorTemplates").toList()) {
@ -76,20 +81,7 @@ RuleTemplates::RuleTemplates(QObject *parent) : QAbstractListModel(parent)
// 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
t->setStateEvaluatorTemplate(loadStateEvaluatorTemplate(ruleTemplate.value("stateEvaluatorTemplate").toMap()));
}
// RuleActionTemplates
@ -167,6 +159,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 +169,7 @@ QHash<int, QByteArray> RuleTemplates::roleNames() const
{
QHash<int, QByteArray> roles;
roles.insert(RoleDescription, "description");
roles.insert(RoleInterfaces, "interfaces");
return roles;
}
@ -186,6 +181,35 @@ RuleTemplate *RuleTemplates::get(int index) const
return m_list.at(index);
}
StateEvaluatorTemplate *RuleTemplates::loadStateEvaluatorTemplate(const QVariantMap &stateEvaluatorTemplate) const
{
QVariantMap stateDescriptorTemplate = stateEvaluatorTemplate.value("stateDescriptorTemplate").toMap();
QMetaEnum selectionModeEnum = QMetaEnum::fromType<StateDescriptorTemplate::SelectionMode>();
QMetaEnum stateOperatorEnum = QMetaEnum::fromType<StateEvaluatorTemplate::StateOperator>();
QMetaEnum valueOperatorEnum = QMetaEnum::fromType<StateDescriptorTemplate::ValueOperator>();
StateEvaluatorTemplate::StateOperator stateOperator = StateEvaluatorTemplate::StateOperatorAnd;
if (stateEvaluatorTemplate.contains("stateOperatorTemplate")) {
stateOperator = static_cast<StateEvaluatorTemplate::StateOperator>(stateOperatorEnum.keyToValue(stateEvaluatorTemplate.value("stateOperatorTemplate").toByteArray().data()));
}
StateEvaluatorTemplate *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>(valueOperatorEnum.keyToValue(stateDescriptorTemplate.value("operator").toByteArray().data())),
stateDescriptorTemplate.value("value")),
stateOperator
);
foreach (const QVariant &childVariant, stateEvaluatorTemplate.value("childEvaluatorTemplates").toList()) {
QVariantMap childMap = childVariant.toMap();
set->childEvaluatorTemplates()->addStateEvaluatorTemplate(loadStateEvaluatorTemplate(childMap.value("stateEvaluatorTemplate").toMap()));
}
return set;
}
bool RuleTemplatesFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
Q_UNUSED(source_parent)
@ -193,40 +217,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 no device in the provided filter proxy implements" << toBeFound;
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)
@ -26,6 +28,9 @@ public:
signals:
void countChanged();
private:
StateEvaluatorTemplate* loadStateEvaluatorTemplate(const QVariantMap &stateEvaluatorTemplate) const;
private:
QList<RuleTemplate*> m_list;
@ -39,12 +44,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 +66,14 @@ 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

@ -90,6 +90,7 @@ signals:
void paramsChanged();
void settingsChanged();
void statesChanged();
void eventTriggered(const QString &eventTypeId, const QVariantMap &params);
};

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

@ -115,6 +115,16 @@ RuleActionParam *RuleActionParams::get(int index) const
return m_list.at(index);
}
bool RuleActionParams::hasRuleActionParam(const QString &paramTypeId) const
{
for (int i = 0; i < m_list.count(); i++) {
if (m_list.at(i)->paramTypeId() == paramTypeId) {
return true;
}
}
return false;
}
bool RuleActionParams::operator==(RuleActionParams *other) const
{
if (rowCount() != other->rowCount()) {

View File

@ -33,6 +33,8 @@ public:
Q_INVOKABLE RuleActionParam* get(int index) const;
Q_INVOKABLE bool hasRuleActionParam(const QString &paramTypeId) const;
bool operator==(RuleActionParams *other) const;
signals:

View File

@ -17,7 +17,7 @@ public:
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
void addStateEvaluator(StateEvaluator* stateEvaluator);
Q_INVOKABLE void addStateEvaluator(StateEvaluator* stateEvaluator);
Q_INVOKABLE StateEvaluator* get(int index) const;
// Caller takes ownership, is responsible for deleting

45
messages.sh Executable file
View File

@ -0,0 +1,45 @@
#!/bin/bash
# Script to update translation files
# Generates ruletemplates/messages.h and calls lupdate on the entire project
# Ideally this would eventually be called in the CI when building the packages
# However, this will break not find all translations when ran with Qt < 5.9
# so for now this is ran manually all the time and results are committed to the
# repository
OUT="nymea-app/ruletemplates/messages.h"
echo "// This file is generated. Update it using ./messages.sh in the root source directory" > $OUT
echo "#include <QString>" >> $OUT
echo "const QString translations[] {" >> $OUT
for INPUTFILE in `ls nymea-app/ruletemplates/*json`; do
echo "Extracting strings from ruletemplate file $INPUTFILE"
FILEBASENAME=$(basename -- "$INPUTFILE")
FILEBASENAME="${FILEBASENAME%.*}"
while IFS= read -r LINE
do
if [[ $LINE == *"\"description\""* ]] || [[ $LINE == *"\"ruleNameTemplate\""* ]]; then
if [ $HASCONTENT -eq 1 ]; then
echo "," >> $OUT
fi
TYPE=`echo $LINE | cut -d ":" -f 1 | sed 's/"//g'`
STRING=`echo $LINE | cut -d ":" -f 2 | sed 's/,$//'`
echo -n "QT_TRANSLATE_NOOP(" >> $OUT
echo -n "\"$TYPE for $FILEBASENAME\", " >> $OUT
echo -n $STRING >> $OUT
echo -n ")" >> $OUT
HASCONTENT=1
fi
done < "$INPUTFILE"
done
echo "" >> $OUT
echo "};" >> $OUT
lupdate nymea-app.pro

View File

@ -42,7 +42,7 @@
#include "stylecontroller.h"
#include "pushnotifications.h"
#include "applogcontroller.h"
#include "ruletemplates/messages.h"
QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{

View File

@ -22,7 +22,8 @@ HEADERS += \
pushnotifications.h \
platformhelper.h \
platformintegration/generic/platformhelpergeneric.h \
applogcontroller.h
applogcontroller.h \
ruletemplates/messages.h
SOURCES += main.cpp \
platformintegration/generic/raspberrypihelper.cpp \
@ -130,10 +131,3 @@ BR=$$BRANDING
target.path = /usr/bin
INSTALLS += target
DISTFILES += \
ruletemplates/smartmetertemplates.json \
ruletemplates/presencesensortemplates.json \
ruletemplates/daylightsensor.json \
ruletemplates/lighttemplates.json

View File

@ -193,5 +193,7 @@
<file>ui/delegates/BrowserItemDelegate.qml</file>
<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

@ -6,6 +6,8 @@
<file>ruletemplates/smartmetertemplates.json</file>
<file>ruletemplates/presencesensortemplates.json</file>
<file>ruletemplates/daylightsensor.json</file>
<file>ruletemplates/lighttemplates.json</file>
<file>ruletemplates/thermostattemplates.json</file>
<file>ruletemplates/mediatemplates.json</file>
<file>ruletemplates/doorbellruletemplates.json</file>
</qresource>
</RCC>

View File

@ -1,7 +1,6 @@
{
"templates": [
{
"interfaceName": "accesscontrol",
"description": "Alert me on denied access attempts",
"ruleNameTemplate": "Denied access attempt on %0",
"eventDescriptorTemplates": [
@ -30,7 +29,6 @@
]
},
{
"interfaceName": "accesscontrol",
"description": "Notify my about access",
"ruleNameTemplate": "Access granted on %0",
"eventDescriptorTemplates": [
@ -59,7 +57,6 @@
]
},
{
"interfaceName": "useraccesscontrol",
"description": "Notify my about user access",
"ruleNameTemplate": "Access granted to user on %0",
"eventDescriptorTemplates": [

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,11 @@
]
},
{
"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",
"interfaceName": "button",
"interfaceEvent": "pressed",
"selectionId": 0,
"selectionMode": "SelectionModeDevice"

View File

@ -1,8 +1,7 @@
{
"templates": [
{
"interfaceName": "daylightsensor",
"description": "Turn on a light while it's dark outside.",
"description": "Turn on a light while it's dark outside",
"ruleNameTemplate": "Turn on %1 while it's dark outside",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
@ -15,7 +14,7 @@
},
"ruleActionTemplates": [
{
"interfaceName": "power",
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"params": [
@ -28,7 +27,7 @@
],
"ruleExitActionTemplates": [
{
"interfaceName": "power",
"interfaceName": "light",
"interfaceAction": "power",
"selectionId": 1,
"params": [
@ -41,9 +40,8 @@
]
},
{
"interfaceName": "daylightsensor",
"description": "Turn on a light when it gets dark outside.",
"ruleNameTemplate": "Turn on %1 it gets dark outside (%0).",
"description": "Turn on a light when it gets dark outside",
"ruleNameTemplate": "Turn on %1 when it gets dark outside (%0)",
"eventDescriptorTemplates": [
{
"interfaceName": "daylightsensor",
@ -73,9 +71,8 @@
]
},
{
"interfaceName": "daylightsensor",
"description": "Turn on all lights when it gets dark outside.",
"ruleNameTemplate": "Turn on all lights when it gets dark outside.",
"description": "Turn on all lights when it gets dark outside",
"ruleNameTemplate": "Turn on all lights when it gets dark outside",
"eventDescriptorTemplates": [
{
"interfaceName": "daylightsensor",

View File

@ -0,0 +1,23 @@
{
"templates": [
{
"description": "Alert on doorbell ring",
"ruleNameTemplate": "Alert %1 when someone is at %0",
"eventDescriptorTemplates": [
{
"interfaceName": "doorbell",
"interfaceEvent": "doorbellPressed",
"selectionId": 0
}
],
"ruleActionTemplates": [
{
"interfaceName": "alert",
"interfaceAction": "alert",
"selectionId": 1
}
]
}
]
}

View File

@ -1,85 +0,0 @@
{
"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

@ -0,0 +1,69 @@
{
"templates": [
{
"description": "Dim light while watching TV",
"ruleNameTemplate": "%0 dims %1 for movie time",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "mediaplayer",
"interfaceState": "playbackStatus",
"selectionId": 0,
"operator": "ValueOperatorEquals",
"value": "Playing"
},
"stateOperatorTemplate": "StateOperatorAnd",
"childEvaluatorTemplates": [
{
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "mediaplayer",
"interfaceState": "playerType",
"selectionId": 0,
"operator": "ValueOperatorEquals",
"value": "video"
}
}
}
]
},
"ruleActionTemplates": [
{
"interfaceName": "dimmablelight",
"interfaceAction": "power",
"selectionId": 1,
"params": [
{
"name": "power",
"value": false
}
]
}
],
"ruleExitActionTemplates": [
{
"interfaceName": "dimmablelight",
"interfaceAction": "power",
"selectionId": 1,
"params": [
{
"name": "power",
"value": true
}
]
},
{
"interfaceName": "dimmablelight",
"interfaceAction": "brightness",
"selectionId": 1,
"params": [
{
"name": "brightness",
"value": "50"
}
]
}
]
}
]
}

View File

@ -0,0 +1,54 @@
// This file is generated. Update it using ./messages.sh in the root source directory
#include <QString>
const QString translations[] {
QT_TRANSLATE_NOOP("description for accesscontroltemplates", "Alert me on denied access attempts"),
QT_TRANSLATE_NOOP("ruleNameTemplate for accesscontroltemplates", "Denied access attempt on %0"),
QT_TRANSLATE_NOOP("description for accesscontroltemplates", "Notify my about access"),
QT_TRANSLATE_NOOP("ruleNameTemplate for accesscontroltemplates", "Access granted on %0"),
QT_TRANSLATE_NOOP("description for accesscontroltemplates", "Notify my about user access"),
QT_TRANSLATE_NOOP("ruleNameTemplate for accesscontroltemplates", "Access granted to user on %0"),
QT_TRANSLATE_NOOP("description for buttontemplates", "Turn on a light"),
QT_TRANSLATE_NOOP("ruleNameTemplate for buttontemplates", "%0 turns on %1"),
QT_TRANSLATE_NOOP("description for buttontemplates", "Turn off a light"),
QT_TRANSLATE_NOOP("ruleNameTemplate for buttontemplates", "%0 turns off %1"),
QT_TRANSLATE_NOOP("description for buttontemplates", "Switch a light"),
QT_TRANSLATE_NOOP("ruleNameTemplate for buttontemplates", "%0 switches %1"),
QT_TRANSLATE_NOOP("description for buttontemplates", "Turn off all lights"),
QT_TRANSLATE_NOOP("ruleNameTemplate for buttontemplates", "Turn off everything with %0"),
QT_TRANSLATE_NOOP("description for daylightsensor", "Turn on a light while it's dark outside"),
QT_TRANSLATE_NOOP("ruleNameTemplate for daylightsensor", "Turn on %1 while it's dark outside"),
QT_TRANSLATE_NOOP("description for daylightsensor", "Turn on a light when it gets dark outside"),
QT_TRANSLATE_NOOP("ruleNameTemplate for daylightsensor", "Turn on %1 when it gets dark outside (%0)"),
QT_TRANSLATE_NOOP("description for daylightsensor", "Turn on all lights when it gets dark outside"),
QT_TRANSLATE_NOOP("ruleNameTemplate for daylightsensor", "Turn on all lights when it gets dark outside"),
QT_TRANSLATE_NOOP("description for doorbellruletemplates", "Alert on doorbell ring"),
QT_TRANSLATE_NOOP("ruleNameTemplate for doorbellruletemplates", "Alert %1 when someone is at %0"),
QT_TRANSLATE_NOOP("description for mediatemplates", "Dim light while watching TV"),
QT_TRANSLATE_NOOP("ruleNameTemplate for mediatemplates", "%0 dims %1 for movie time"),
QT_TRANSLATE_NOOP("description for notificationtemplates", "Notify me when a device runs out of battery"),
QT_TRANSLATE_NOOP("ruleNameTemplate for notificationtemplates", "Low battery alert for %0"),
QT_TRANSLATE_NOOP("description for notificationtemplates", "Notify me when something runs dry"),
QT_TRANSLATE_NOOP("ruleNameTemplate for notificationtemplates", "Notify %1 when %0 runs dry"),
QT_TRANSLATE_NOOP("description for notificationtemplates", "Notify me when a thing gets disconnected"),
QT_TRANSLATE_NOOP("ruleNameTemplate for notificationtemplates", "Disconnect alert for %0"),
QT_TRANSLATE_NOOP("description for notificationtemplates", "Notify me when a thing connects"),
QT_TRANSLATE_NOOP("ruleNameTemplate for notificationtemplates", "Connection notification for %0"),
QT_TRANSLATE_NOOP("description for presencesensortemplates", "Turn on something while being present"),
QT_TRANSLATE_NOOP("ruleNameTemplate for presencesensortemplates", "Turn on %1 while %0 reports presence"),
QT_TRANSLATE_NOOP("description for presencesensortemplates", "Turn off something when leaving"),
QT_TRANSLATE_NOOP("ruleNameTemplate for presencesensortemplates", "Turn off %1 when %0 reports leaving"),
QT_TRANSLATE_NOOP("description for presencesensortemplates", "Turn off everything when leaving"),
QT_TRANSLATE_NOOP("ruleNameTemplate for presencesensortemplates", "Turn off everything when %0 reports leaving"),
QT_TRANSLATE_NOOP("description for presencesensortemplates", "Turn off all lights when leaving"),
QT_TRANSLATE_NOOP("ruleNameTemplate for presencesensortemplates", "Turn off all lights when %0 reports leaving"),
QT_TRANSLATE_NOOP("description for presencesensortemplates", "Turn on something when arriving"),
QT_TRANSLATE_NOOP("ruleNameTemplate for presencesensortemplates", "Turn on %1 when %0 reports arriving"),
QT_TRANSLATE_NOOP("description for smartmetertemplates", "Charge my car while producing energy"),
QT_TRANSLATE_NOOP("ruleNameTemplate for smartmetertemplates", "Smart car charging"),
QT_TRANSLATE_NOOP("description for smartmetertemplates", "Turn on heating while producing energy"),
QT_TRANSLATE_NOOP("ruleNameTemplate for smartmetertemplates", "Smart heating"),
QT_TRANSLATE_NOOP("description for template", ""),
QT_TRANSLATE_NOOP("ruleNameTemplate for template", "%0 ..."),
QT_TRANSLATE_NOOP("description for thermostattemplates", "Set temperature while I'm home"),
QT_TRANSLATE_NOOP("ruleNameTemplate for thermostattemplates", "Set temperature while I'm home")
};

View File

@ -1,7 +1,6 @@
{
"templates": [
{
"interfaceName": "notifications",
"description": "Notify me when a device runs out of battery",
"ruleNameTemplate": "Low battery alert for %0",
"stateEvaluatorTemplate": {
@ -33,7 +32,37 @@
]
},
{
"interfaceName": "notifications",
"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": {
@ -66,7 +95,6 @@
]
},
{
"interfaceName": "notifications",
"description": "Notify me when a thing connects",
"ruleNameTemplate": "Connection notification for %0",
"stateEvaluatorTemplate": {
@ -88,7 +116,7 @@
"params": [
{
"name": "title",
"value": "Thin connected"
"value": "Thing connected"
},
{
"name": "body",

View File

@ -1,9 +1,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",
@ -41,9 +40,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",
@ -73,9 +71,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",
@ -106,9 +103,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",
@ -139,9 +135,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,8 +1,7 @@
{
"templates": [
{
"interfaceName": "extendedsmartmeterproducer",
"description": "Charge my car while producing energy.",
"description": "Charge my car while producing energy",
"ruleNameTemplate": "Smart car charging",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
@ -41,8 +40,7 @@
]
},
{
"interfaceName": "extendedsmartmeterproducer",
"description": "Turn on heating while producing energy.",
"description": "Turn on heating while producing energy",
"ruleNameTemplate": "Smart heating",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {

View File

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

View File

@ -0,0 +1,38 @@
{
"templates": [
{
"description": "Set temperature while I'm home",
"ruleNameTemplate": "Set temperature while I'm home",
"stateEvaluatorTemplate": {
"stateDescriptorTemplate": {
"interfaceName": "presencesensor",
"interfaceState": "isPresent",
"selectionId": 0,
"operator": "ValueOperatorEquals",
"value": true
}
},
"ruleActionTemplates": [
{
"interfaceName": "thermostat",
"interfaceAction": "targetTemperature",
"selectionId": 1
}
],
"ruleExitActionTemplates": [
{
"interfaceName": "thermostat",
"interfaceAction": "targetTemperature",
"selectionId": 1,
"params": [
{
"name": "targetTemperature",
"value": "16"
}
]
}
]
}
]
}

View File

@ -716,6 +716,14 @@
<source>Log in to %1:cloud in order to connect to %1:core systems from anywhere.</source>
<translation>Melde Dich bei %1:cloud an um von überall aus auf Deine %1:core Systeme zugreifen zu können.</translation>
</message>
<message>
<source>Failed to connect to the login server. Please mase sure your network connection is working.</source>
<translation>Fehler beim verbinden zum Login-Server. Bitte stelle sicher, dass Deine Netzwerkverbindung funktioniert.</translation>
</message>
<message>
<source>An unexpected error happened. Please report this isse. Error code:</source>
<translation>Ein Unerwartetet Fehler ist aufgetreten. Bitte benachrichtige uns darüber. Fehler code:</translation>
</message>
</context>
<context>
<name>CloudSettingsPage</name>
@ -1345,6 +1353,13 @@
<translation type="vanished">%1 installiert</translation>
</message>
</context>
<context>
<name>DoorbellDevicePage</name>
<message>
<source>History</source>
<translation>Verlauf</translation>
</message>
</context>
<context>
<name>EditCalendarItemPage</name>
<message>
@ -3338,6 +3353,13 @@ Möchtest Du fortfahren?</translation>
<translation type="vanished">OK</translation>
</message>
</context>
<context>
<name>NewMagicPage</name>
<message>
<source>New magic</source>
<translation>Neue Magie</translation>
</message>
</context>
<context>
<name>NewThingMagicPage</name>
<message>
@ -3348,6 +3370,10 @@ Möchtest Du fortfahren?</translation>
<source>Create some magic manually</source>
<translation>Magie manuell erstellen</translation>
</message>
<message>
<source>New magic for %1</source>
<translation>Neue Magie für %1</translation>
</message>
</context>
<context>
<name>NewThingPage</name>
@ -3564,6 +3590,34 @@ Möchtest Du fortfahren?</translation>
<source>presence sensor</source>
<translation>Anwesenheitssensor</translation>
</message>
<message>
<source>Doorbells</source>
<translation>Türklingeln</translation>
</message>
<message>
<source>doorbell</source>
<translation>Türklingel</translation>
</message>
<message>
<source>alert</source>
<translation>Alarm</translation>
</message>
<message>
<source>button</source>
<translation>Taster</translation>
</message>
<message>
<source>access control</source>
<translation>Zugangskontrolle</translation>
</message>
<message>
<source>smart meter</source>
<translation>Smart Meter</translation>
</message>
<message>
<source>media player</source>
<translation>Medienabspielgerät</translation>
</message>
</context>
<context>
<name>NymeaConnection</name>
@ -5005,6 +5059,129 @@ Bitte warte bis diese abgeschlossen ist.</translation>
<translation>Verbinde zu %1:core</translation>
</message>
</context>
<context>
<name>description for accesscontroltemplates</name>
<message>
<source>Alert me on denied access attempts</source>
<translation>Benachritige mich bei Fehlgeschlagenen Zutrittsversuchen</translation>
</message>
<message>
<source>Notify my about access</source>
<translation>Benachrichtige me über Zugänge</translation>
</message>
<message>
<source>Notify my about user access</source>
<translation>Benachrichtige mich über Benutzerzugang</translation>
</message>
</context>
<context>
<name>description for buttontemplates</name>
<message>
<source>Turn on a light</source>
<translation>Ein Licht einschalten</translation>
</message>
<message>
<source>Turn off a light</source>
<translation>Ein Licht ausschalten</translation>
</message>
<message>
<source>Switch a light</source>
<translation>Ein Licht schalten</translation>
</message>
<message>
<source>Turn off all lights</source>
<translation>Alle Lichter ausschalten</translation>
</message>
</context>
<context>
<name>description for daylightsensor</name>
<message>
<source>Turn on a light while it&apos;s dark outside</source>
<translation>Ein Licht einschalten während es dunkel ist</translation>
</message>
<message>
<source>Turn on a light when it gets dark outside</source>
<translation>Ein Licht einschalten wenn es dunkel wird</translation>
</message>
<message>
<source>Turn on all lights when it gets dark outside</source>
<translation>Alle Lichter einschlalten wenn es dunkel wird</translation>
</message>
</context>
<context>
<name>description for doorbellruletemplates</name>
<message>
<source>Alert on doorbell ring</source>
<translation>Signal bei Türklingelbetätigung</translation>
</message>
</context>
<context>
<name>description for mediatemplates</name>
<message>
<source>Dim light while watching TV</source>
<translation>Licht dimmen während TV-Wiedergabe</translation>
</message>
</context>
<context>
<name>description for notificationtemplates</name>
<message>
<source>Notify me when a device runs out of battery</source>
<translation>Benachrichtige mich wenn sich die Batterie eines Gerätes zu Ende neight</translation>
</message>
<message>
<source>Notify me when something runs dry</source>
<translation>Benachrichte mich wenn etwas austrocknet</translation>
</message>
<message>
<source>Notify me when a thing gets disconnected</source>
<translation>Benachrichtuge mich wenn ein Gerät die Verbindung verliert</translation>
</message>
<message>
<source>Notify me when a thing connects</source>
<translation>Benachrichtige mich wenn sich ein Gerät verbindet</translation>
</message>
</context>
<context>
<name>description for presencesensortemplates</name>
<message>
<source>Turn on something while being present</source>
<translation>Etwas einschalten während Anwesenheit</translation>
</message>
<message>
<source>Turn off something when leaving</source>
<translation>Etwas ausschalten beim Verlassen</translation>
</message>
<message>
<source>Turn off everything when leaving</source>
<translation>Alles ausschalten beim Verlassen</translation>
</message>
<message>
<source>Turn off all lights when leaving</source>
<translation>Alle Lichter beim Verlassen ausschalten</translation>
</message>
<message>
<source>Turn on something when arriving</source>
<translation>Etwas einschalten bei Ankunft</translation>
</message>
</context>
<context>
<name>description for smartmetertemplates</name>
<message>
<source>Charge my car while producing energy</source>
<translation>Fahrzeug laden während Strom erzeugt wird</translation>
</message>
<message>
<source>Turn on heating while producing energy</source>
<translation>Heizung einschalten während Strom erzeugt wird</translation>
</message>
</context>
<context>
<name>description for thermostattemplates</name>
<message>
<source>Set temperature while I&apos;m home</source>
<translation>Temperatur einstellen während ich zuhause bin</translation>
</message>
</context>
<context>
<name>main</name>
<message>
@ -5064,4 +5241,134 @@ Bitte warte bis diese abgeschlossen ist.</translation>
<translation type="vanished">OK</translation>
</message>
</context>
<context>
<name>ruleNameTemplate for accesscontroltemplates</name>
<message>
<source>Denied access attempt on %0</source>
<translation>Verweigerter Zutrittsversuch bei %0</translation>
</message>
<message>
<source>Access granted on %0</source>
<translation>Zugang erteikt bei %0</translation>
</message>
<message>
<source>Access granted to user on %0</source>
<translation>Zuggang für Benutzer bei %0 erlaubt</translation>
</message>
</context>
<context>
<name>ruleNameTemplate for buttontemplates</name>
<message>
<source>%0 turns on %1</source>
<translation>0% schaltet %1 ein</translation>
</message>
<message>
<source>%0 turns off %1</source>
<translation>%0 schaltet %1 aus</translation>
</message>
<message>
<source>%0 switches %1</source>
<translation>%0 schaltet %1</translation>
</message>
<message>
<source>Turn off everything with %0</source>
<translation>Alles ausschalten mit %0</translation>
</message>
</context>
<context>
<name>ruleNameTemplate for daylightsensor</name>
<message>
<source>Turn on %1 while it&apos;s dark outside</source>
<translation>%1 einschalten während es drausen dunkel ist</translation>
</message>
<message>
<source>Turn on %1 when it gets dark outside (%0)</source>
<translation>Schalte %1 ein wenn es drausen dunkel wird (%0)</translation>
</message>
<message>
<source>Turn on all lights when it gets dark outside</source>
<translation>Alle Lichter einschalten wenn es drausen dunkel wird</translation>
</message>
</context>
<context>
<name>ruleNameTemplate for doorbellruletemplates</name>
<message>
<source>Alert %1 when someone is at %0</source>
<translation>Signal bei %1 wenn jemand bei %0 ist</translation>
</message>
</context>
<context>
<name>ruleNameTemplate for mediatemplates</name>
<message>
<source>%0 dims %1 for movie time</source>
<translation>%0 dimmt %1 für Fernsehzeit</translation>
</message>
</context>
<context>
<name>ruleNameTemplate for notificationtemplates</name>
<message>
<source>Low battery alert for %0</source>
<translation>Batterieladung kritisch bei %0</translation>
</message>
<message>
<source>Notify %1 when %0 runs dry</source>
<translation>Benachrichtige %1 wenn %0 austrocknet</translation>
</message>
<message>
<source>Disconnect alert for %0</source>
<translation>%0 wurde getrennt</translation>
</message>
<message>
<source>Connection notification for %0</source>
<translation>%0 wurde verbunden</translation>
</message>
</context>
<context>
<name>ruleNameTemplate for presencesensortemplates</name>
<message>
<source>Turn on %1 while %0 reports presence</source>
<translation>%1 einschalten während %0 Anwesenheit registriert</translation>
</message>
<message>
<source>Turn off %1 when %0 reports leaving</source>
<translation>%1 ausschalten wenn %0 verlassen wird</translation>
</message>
<message>
<source>Turn off everything when %0 reports leaving</source>
<translation>Alles ausschalten wenn %0 verlassen wird</translation>
</message>
<message>
<source>Turn off all lights when %0 reports leaving</source>
<translation>Alle Lichter ausschalten wenn %0 verlassen wird</translation>
</message>
<message>
<source>Turn on %1 when %0 reports arriving</source>
<translation>%1 einschalten %0 Ankunft registiert</translation>
</message>
</context>
<context>
<name>ruleNameTemplate for smartmetertemplates</name>
<message>
<source>Smart car charging</source>
<translation>Intelligentes Fahrzeugladen</translation>
</message>
<message>
<source>Smart heating</source>
<translation>Intelligente Heizung</translation>
</message>
</context>
<context>
<name>ruleNameTemplate for template</name>
<message>
<source>%0 ...</source>
<translation></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for thermostattemplates</name>
<message>
<source>Set temperature while I&apos;m home</source>
<translation>Setze Temperatur während ich zuhause bin</translation>
</message>
</context>
</TS>

View File

@ -496,6 +496,14 @@
<source>Log in to %1:cloud in order to connect to %1:core systems from anywhere.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to connect to the login server. Please mase sure your network connection is working.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>An unexpected error happened. Please report this isse. Error code:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>CloudSettingsPage</name>
@ -926,6 +934,13 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DoorbellDevicePage</name>
<message>
<source>History</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditCalendarItemPage</name>
<message>
@ -2572,6 +2587,13 @@ Please try again.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewMagicPage</name>
<message>
<source>New magic</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewThingMagicPage</name>
<message>
@ -2582,6 +2604,10 @@ Please try again.</source>
<source>Create some magic manually</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>New magic for %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewThingPage</name>
@ -2782,6 +2808,34 @@ Please try again.</source>
<source>presence sensor</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Doorbells</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>doorbell</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>alert</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>button</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>access control</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>smart meter</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>media player</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NymeaConnection</name>
@ -3792,4 +3846,257 @@ Do you want to proceed?</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for accesscontroltemplates</name>
<message>
<source>Alert me on denied access attempts</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify my about access</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify my about user access</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for buttontemplates</name>
<message>
<source>Turn on a light</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off a light</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Switch a light</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off all lights</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for daylightsensor</name>
<message>
<source>Turn on a light while it&apos;s dark outside</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on a light when it gets dark outside</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on all lights when it gets dark outside</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for doorbellruletemplates</name>
<message>
<source>Alert on doorbell ring</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for mediatemplates</name>
<message>
<source>Dim light while watching TV</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for notificationtemplates</name>
<message>
<source>Notify me when a device runs out of battery</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify me when something runs dry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify me when a thing gets disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify me when a thing connects</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for presencesensortemplates</name>
<message>
<source>Turn on something while being present</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off something when leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off everything when leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off all lights when leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on something when arriving</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for smartmetertemplates</name>
<message>
<source>Charge my car while producing energy</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on heating while producing energy</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for thermostattemplates</name>
<message>
<source>Set temperature while I&apos;m home</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for accesscontroltemplates</name>
<message>
<source>Denied access attempt on %0</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Access granted on %0</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Access granted to user on %0</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for buttontemplates</name>
<message>
<source>%0 turns on %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%0 turns off %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%0 switches %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off everything with %0</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for daylightsensor</name>
<message>
<source>Turn on %1 while it&apos;s dark outside</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on %1 when it gets dark outside (%0)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on all lights when it gets dark outside</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for doorbellruletemplates</name>
<message>
<source>Alert %1 when someone is at %0</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for mediatemplates</name>
<message>
<source>%0 dims %1 for movie time</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for notificationtemplates</name>
<message>
<source>Low battery alert for %0</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify %1 when %0 runs dry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disconnect alert for %0</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Connection notification for %0</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for presencesensortemplates</name>
<message>
<source>Turn on %1 while %0 reports presence</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off %1 when %0 reports leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off everything when %0 reports leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off all lights when %0 reports leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on %1 when %0 reports arriving</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for smartmetertemplates</name>
<message>
<source>Smart car charging</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Smart heating</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for template</name>
<message>
<source>%0 ...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for thermostattemplates</name>
<message>
<source>Set temperature while I&apos;m home</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -331,13 +331,14 @@
<source>There are %n boxes connected to your cloud</source>
<translation type="obsolete">
<numerusform>There is %n box connected to your cloud.</numerusform>
<numerusform>There are %n boxes connected to your cloud.</numerusform>
</translation>
</message>
<message numerus="yes">
<source>There are %n boxes connected to your cloud.</source>
<translation><numerusform>%n () .</numerusform>
</translation></message>
<translation type="vanished">
<numerusform>%n () .</numerusform>
</translation>
</message>
<message>
<source>Cloud login</source>
<translation> </translation>
@ -480,8 +481,10 @@
</message>
<message numerus="yes">
<source>There are %n %1:core systems connected to your cloud.</source>
<translation><numerusform>%n %1:코어 .</numerusform>
</translation></message>
<translation>
<numerusform>%n %1:코어 .</numerusform>
</translation>
</message>
<message>
<source>Sorry to see you go. If you log out you won&apos;t be able to connect to %1:core systems remotely any more. However, you can come back any time, we&apos;ll keep your user account. If you whish to completely delete your account and all the data associated with it, check the box below before hitting ok. If you decide to delete your account, all your personal information will be removed from %1:cloud and cannot be restored.</source>
<translation>. %1:코어 . , . . %1:클라우드에서 .</translation>
@ -490,6 +493,14 @@
<source>Log in to %1:cloud in order to connect to %1:core systems from anywhere.</source>
<translation> %1:core %1:cloud에 .</translation>
</message>
<message>
<source>Failed to connect to the login server. Please mase sure your network connection is working.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>An unexpected error happened. Please report this isse. Error code:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>CloudSettingsPage</name>
@ -920,6 +931,13 @@
<translation>%1 </translation>
</message>
</context>
<context>
<name>DoorbellDevicePage</name>
<message>
<source>History</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditCalendarItemPage</name>
<message>
@ -2245,8 +2263,10 @@ Please try again.</source>
</message>
<message numerus="yes">
<source>%n system update(s) available</source>
<translation><numerusform>%n </numerusform>
</translation></message>
<translation>
<numerusform>%n </numerusform>
</translation>
</message>
<message>
<source>System settings</source>
<translation> </translation>
@ -2570,6 +2590,13 @@ Please try again.</source>
<translation>WiFi를 WiFi를 . LAN %1 .</translation>
</message>
</context>
<context>
<name>NewMagicPage</name>
<message>
<source>New magic</source>
<translation type="unfinished"> </translation>
</message>
</context>
<context>
<name>NewThingMagicPage</name>
<message>
@ -2580,6 +2607,10 @@ Please try again.</source>
<source>Create some magic manually</source>
<translation> </translation>
</message>
<message>
<source>New magic for %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewThingPage</name>
@ -2780,6 +2811,34 @@ Please try again.</source>
<source>presence sensor</source>
<translation> </translation>
</message>
<message>
<source>Doorbells</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>doorbell</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>alert</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>button</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>access control</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>smart meter</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>media player</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NymeaConnection</name>
@ -3515,8 +3574,10 @@ Please only use this if you are sure you want this and consider reporting the is
</message>
<message numerus="yes">
<source>%n update(s) available</source>
<translation><numerusform>%n </numerusform>
</translation></message>
<translation>
<numerusform>%n </numerusform>
</translation>
</message>
<message>
<source>Check again</source>
<translation> </translation>
@ -3788,4 +3849,257 @@ Do you want to proceed?</source>
<translation>%1:코어에 </translation>
</message>
</context>
<context>
<name>description for accesscontroltemplates</name>
<message>
<source>Alert me on denied access attempts</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify my about access</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify my about user access</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for buttontemplates</name>
<message>
<source>Turn on a light</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off a light</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Switch a light</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off all lights</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for daylightsensor</name>
<message>
<source>Turn on a light while it&apos;s dark outside</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on a light when it gets dark outside</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on all lights when it gets dark outside</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for doorbellruletemplates</name>
<message>
<source>Alert on doorbell ring</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for mediatemplates</name>
<message>
<source>Dim light while watching TV</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for notificationtemplates</name>
<message>
<source>Notify me when a device runs out of battery</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify me when something runs dry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify me when a thing gets disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify me when a thing connects</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for presencesensortemplates</name>
<message>
<source>Turn on something while being present</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off something when leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off everything when leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off all lights when leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on something when arriving</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for smartmetertemplates</name>
<message>
<source>Charge my car while producing energy</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on heating while producing energy</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>description for thermostattemplates</name>
<message>
<source>Set temperature while I&apos;m home</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for accesscontroltemplates</name>
<message>
<source>Denied access attempt on %0</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Access granted on %0</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Access granted to user on %0</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for buttontemplates</name>
<message>
<source>%0 turns on %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%0 turns off %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%0 switches %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off everything with %0</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for daylightsensor</name>
<message>
<source>Turn on %1 while it&apos;s dark outside</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on %1 when it gets dark outside (%0)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on all lights when it gets dark outside</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for doorbellruletemplates</name>
<message>
<source>Alert %1 when someone is at %0</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for mediatemplates</name>
<message>
<source>%0 dims %1 for movie time</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for notificationtemplates</name>
<message>
<source>Low battery alert for %0</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Notify %1 when %0 runs dry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disconnect alert for %0</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Connection notification for %0</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for presencesensortemplates</name>
<message>
<source>Turn on %1 while %0 reports presence</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off %1 when %0 reports leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off everything when %0 reports leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn off all lights when %0 reports leaving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Turn on %1 when %0 reports arriving</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for smartmetertemplates</name>
<message>
<source>Smart car charging</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Smart heating</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for template</name>
<message>
<source>%0 ...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ruleNameTemplate for thermostattemplates</name>
<message>
<source>Set temperature while I&apos;m home</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

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

@ -65,7 +65,7 @@ ApplicationWindow {
}
property alias _discovery: discovery
property var supportedInterfaces: ["light", "weather", "media", "garagegate", "awning", "shutter", "blind", "powersocket", "heating", "sensor", "smartmeter", "evcharger", "accesscontrol", "button", "notifications", "inputtrigger", "outputtrigger", "gateway"]
property var supportedInterfaces: ["light", "weather", "media", "garagegate", "awning", "shutter", "blind", "powersocket", "heating", "doorbell", "sensor", "smartmeter", "evcharger", "accesscontrol", "button", "notifications", "inputtrigger", "outputtrigger", "gateway"]
function interfaceToString(name) {
switch(name) {
case "light":
@ -122,6 +122,8 @@ ApplicationWindow {
return qsTr("EV-chargers");
case "powersocket":
return qsTr("Power sockets")
case "doorbell":
return qsTr("Doorbells");
case "uncategorized":
return qsTr("Uncategorized")
default:
@ -145,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")
@ -172,6 +175,7 @@ ApplicationWindow {
return Qt.resolvedUrl("images/sensors/closable.svg")
case "media":
case "mediacontroller":
case "mediaplayer":
return Qt.resolvedUrl("images/mediaplayer-app-symbolic.svg")
case "powersocket":
return Qt.resolvedUrl("images/powersocket.svg")
@ -226,8 +230,12 @@ ApplicationWindow {
case "evcharger":
case "extendedevcharger":
return Qt.resolvedUrl("images/ev-charger.svg")
case "doorbell":
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)
}
@ -270,6 +278,9 @@ ApplicationWindow {
function interfaceToDisplayName(name) {
switch (name) {
case "light":
case "dimmablelight":
case "colorlight":
case "colortemperaturelight":
return qsTr("light")
case "button":
return "button";
@ -285,6 +296,24 @@ ApplicationWindow {
return qsTr("daylight sensor")
case "presencesensor":
return qsTr("presence sensor")
case "doorbell":
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");
case "media":
case "mediaplayer":
return qsTr("media player")
default:
console.warn("Unhandled interfaceToDisplayName:", name)
}
@ -322,6 +351,8 @@ ApplicationWindow {
page = "SmartMeterDevicePage.qml"
} else if (interfaceList.indexOf("powersocket") >= 0) {
page = "PowersocketDevicePage.qml";
} else if (interfaceList.indexOf("doorbell") >= 0) {
page = "DoorbellDevicePage.qml";
} else {
page = "GenericDevicePage.qml";
}

View File

@ -91,7 +91,6 @@ Item {
Label {
text: infoPane.text
visible: infoPane.alertState
font.pixelSize: app.smallFont
color: "white"
}

View File

@ -13,6 +13,7 @@ SwipeDelegate {
property bool wrapTexts: true
property bool prominentSubText: true
property int textAlignment: Text.AlignLeft
property string iconName
property string thumbnail
@ -81,6 +82,7 @@ SwipeDelegate {
maximumLineCount: root.wrapTexts ? 2 : 1
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: root.textAlignment
}
Label {
Layout.fillWidth: true

View File

@ -0,0 +1,111 @@
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
readonly property EventType doorbellPressedType: deviceClass.eventTypes.findByName("doorbellPressed")
GridLayout {
anchors.fill: parent
anchors.topMargin: app.margins
columns: app.landscape ? 2 : 1
columnSpacing: app.margins
rowSpacing: app.margins
Item {
Layout.fillWidth: true
Layout.fillHeight: true
ColorIcon {
id: doorbellIcon
anchors.centerIn: parent
height: Math.min(parent.width, parent.height)
width: height
name: "../images/notification.svg"
color: keyColor
SequentialAnimation {
id: ringAnimation
ColorAnimation { target: doorbellIcon; property: "color"; from: doorbellIcon.keyColor; to: app.accentColor; duration: 200 }
ColorAnimation { target: doorbellIcon; property: "color"; from: app.accentColor; to: doorbellIcon.keyColor; duration: 300 }
ColorAnimation { target: doorbellIcon; property: "color"; from: doorbellIcon.keyColor; to: app.accentColor; duration: 200 }
ColorAnimation { target: doorbellIcon; property: "color"; from: app.accentColor; to: doorbellIcon.keyColor; duration: 300 }
ColorAnimation { target: doorbellIcon; property: "color"; from: doorbellIcon.keyColor; to: app.accentColor; duration: 200 }
ColorAnimation { target: doorbellIcon; property: "color"; from: app.accentColor; to: doorbellIcon.keyColor; duration: 300 }
ColorAnimation { target: doorbellIcon; property: "color"; from: doorbellIcon.keyColor; to: app.accentColor; duration: 200 }
ColorAnimation { target: doorbellIcon; property: "color"; from: app.accentColor; to: doorbellIcon.keyColor; duration: 300 }
}
Connections {
target: root.device
onEventTriggered: {
print("evenEmitted", params)
if (eventTypeId == root.doorbellPressedType.id) {
ringAnimation.start();
}
}
}
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
ColumnLayout {
anchors.fill: parent
spacing: app.margins
ThinDivider {
visible: !app.landscape
}
RowLayout {
spacing: app.margins
Label {
Layout.fillWidth: true
}
ColorIcon {
Layout.preferredHeight: app.iconSize
Layout.preferredWidth: app.iconSize
name: "../images/alarm-clock.svg"
color: app.accentColor
}
Label {
text: qsTr("History")
}
Label {
Layout.fillWidth: true
}
}
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
model: LogsModelNg {
engine: _engine
live: true
deviceId: root.device.id
typeIds: [root.doorbellPressedType.id]
}
delegate: NymeaListItemDelegate {
width: parent.width
text: Qt.formatDateTime(model.timestamp)
progressive: false
textAlignment: Text.AlignHCenter
}
}
}
}
}
}

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 : []
}
@ -78,7 +79,6 @@ Page {
Connections {
target: engine.ruleManager
onAddRuleReply: {
d.editRulePage.busy = false;
if (ruleError == "RuleErrorNoError") {
pageStack.pop(root);
} else {
@ -86,10 +86,10 @@ Page {
var popup = errorDialog.createObject(root, {errorCode: ruleError })
popup.open();
}
d.editRulePage.busy = false;
}
onEditRuleReply: {
d.editRulePage.busy = false;
if (ruleError == "RuleErrorNoError") {
pageStack.pop(root);
} else {
@ -97,6 +97,7 @@ Page {
var popup = errorDialog.createObject(root, {errorCode: ruleError })
popup.open();
}
d.editRulePage.busy = false;
}
}

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;
@ -257,10 +265,14 @@ Page {
return true;
}
stateEvaluator.stateOperator = stateEvaluatorTemplate.stateOperator;
print("Added stateOperator", stateEvaluator.stateOperator)
if (stateEvaluatorTemplate.childEvaluatorTemplates.count > stateEvaluator.childEvaluators.count) {
print("Adding more child evaluators. Have:", stateEvaluator.childEvaluators.count, "need:", stateEvaluatorTemplate.childEvaluatorTemplates.count)
print("getting", stateEvaluator.childEvaluators.count)
print("getting", stateEvaluatorTemplate.childEvaluatorTemplates.get(stateEvaluator.childEvaluators.count))
var childEvaluator = rule.createStateEvaluator();
var more = fillStateEvaluatorFromTemplate(rule, ruleTemplate, childEvaluator, stateEvaluatorTemplate.childEvaluatorTemplates.get(stateEvaluator.childEvaluators.count))
stateEvaluator.childEvaluators.addStateEvaluator(childEvaluator);
var more = fillStateEvaluatorFromTemplate(rule, ruleTemplate, childEvaluator, stateEvaluatorTemplate.childEvaluatorTemplates.get(stateEvaluator.childEvaluators.count-1))
return more;
}
return false;
@ -272,15 +284,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() {
@ -300,12 +317,15 @@ Page {
function createRuleAction(rule, ruleTemplate, ruleActions, device, ruleActionTemplate) {
var ruleAction = ruleActions.createNewRuleAction();
var deviceClass = engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleActionTemplate.interfaceAction).id
ruleAction.deviceId = device.id;
print("Creating action", ruleActionTemplate.interfaceAction, "on device class", deviceClass.displayName)
ruleAction.actionTypeId = deviceClass.actionTypes.findByName(ruleActionTemplate.interfaceAction).id
var actionType = deviceClass.actionTypes.getActionType(ruleAction.actionTypeId);
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)
@ -335,8 +355,26 @@ Page {
} else {
console.warn("Invalid RuleActionParamTemplate. Has neither value nor event spec")
}
}
// Check if the action has more paramTypes than there are defined in the ruleActionTemplate
for (var i = 0; i < actionType.paramTypes.count; i++) {
var paramType = actionType.paramTypes.get(i);
if (!ruleAction.ruleActionParams.hasRuleActionParam(paramType.id)) {
print("Missing param!", paramType.name)
var paramsPage = pageStack.push(Qt.resolvedUrl("SelectRuleActionParamsPage.qml"), {ruleAction: ruleAction, rule: rule})
paramsPage.onBackPressed.connect(function() {
ruleAction.destroy()
pageStack.pop();
});
paramsPage.onCompleted.connect(function() {
pageStack.pop();
ruleActions.addRuleAction(ruleAction);
fillRuleFromTemplate(rule, ruleTemplate);
})
return;
}
}
ruleActions.addRuleAction(ruleAction);
fillRuleFromTemplate(rule, ruleTemplate);
}
@ -352,7 +390,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()
}
@ -361,14 +399,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

@ -187,7 +187,9 @@ Page {
for (var i = 0; i < delegateRepeater.count; i++) {
var paramDelegate = delegateRepeater.itemAt(i);
if (paramDelegate.type === "static") {
print("Setting static value", paramDelegate.value)
if (root.device) {
print("setting", paramDelegate.paramType.id)
root.ruleAction.ruleActionParams.setRuleActionParam(paramDelegate.paramType.id, paramDelegate.value)
} else if (root.iface) {
root.ruleAction.ruleActionParams.setRuleActionParamByName(root.actionType.paramTypes.get(i).name, paramDelegate.value)

View File

@ -43,6 +43,9 @@ Page {
engine: _engine
groupByInterface: true
nameFilter: filterInput.shown ? filterInput.text : ""
Component.onCompleted: {
print("showing devices for interfaces", devicesProxy.shownInterfaces)
}
}
ColumnLayout {

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]})
}
}