Merge PR #234: Improve rule creation
This commit is contained in:
commit
63cb1b4ced
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -120,6 +120,8 @@ signals:
|
||||
void fetchingDataChanged();
|
||||
void notificationReceived(const QString &deviceId, const QString &eventTypeId, const QVariantList ¶ms);
|
||||
|
||||
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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -28,7 +28,7 @@ class JsonHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
JsonHandler(QObject *parent = 0);
|
||||
JsonHandler(QObject *parent = nullptr);
|
||||
virtual QString nameSpace() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -90,6 +90,7 @@ signals:
|
||||
void paramsChanged();
|
||||
void settingsChanged();
|
||||
void statesChanged();
|
||||
void eventTriggered(const QString &eventTypeId, const QVariantMap ¶ms);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -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 ¶mTypeId) 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 ¶mName) 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()) {
|
||||
|
||||
@ -42,6 +42,9 @@ public:
|
||||
Q_INVOKABLE void setParamDescriptorByName(const QString ¶mName, const QVariant &value, ValueOperator operatorType);
|
||||
Q_INVOKABLE void clear();
|
||||
|
||||
Q_INVOKABLE ParamDescriptor *getParamDescriptor(const QString ¶mTypeId) const;
|
||||
Q_INVOKABLE ParamDescriptor *getParamDescriptorByName(const QString ¶mName) const;
|
||||
|
||||
bool operator==(ParamDescriptors *other) const;
|
||||
|
||||
signals:
|
||||
|
||||
@ -115,6 +115,16 @@ RuleActionParam *RuleActionParams::get(int index) const
|
||||
return m_list.at(index);
|
||||
}
|
||||
|
||||
bool RuleActionParams::hasRuleActionParam(const QString ¶mTypeId) 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()) {
|
||||
|
||||
@ -33,6 +33,8 @@ public:
|
||||
|
||||
Q_INVOKABLE RuleActionParam* get(int index) const;
|
||||
|
||||
Q_INVOKABLE bool hasRuleActionParam(const QString ¶mTypeId) const;
|
||||
|
||||
bool operator==(RuleActionParams *other) const;
|
||||
|
||||
signals:
|
||||
|
||||
@ -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
45
messages.sh
Executable 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
|
||||
@ -42,7 +42,7 @@
|
||||
#include "stylecontroller.h"
|
||||
#include "pushnotifications.h"
|
||||
#include "applogcontroller.h"
|
||||
|
||||
#include "ruletemplates/messages.h"
|
||||
|
||||
QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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": [
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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",
|
||||
|
||||
23
nymea-app/ruletemplates/doorbellruletemplates.json
Normal file
23
nymea-app/ruletemplates/doorbellruletemplates.json
Normal 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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
69
nymea-app/ruletemplates/mediatemplates.json
Normal file
69
nymea-app/ruletemplates/mediatemplates.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
54
nymea-app/ruletemplates/messages.h
Normal file
54
nymea-app/ruletemplates/messages.h
Normal 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")
|
||||
};
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{
|
||||
"templates": [
|
||||
{
|
||||
"interfaceName": "",
|
||||
"description": "",
|
||||
"ruleNameTemplate": "%0 ...",
|
||||
"eventDescriptorTemplates": [ // optional
|
||||
|
||||
38
nymea-app/ruletemplates/thermostattemplates.json
Normal file
38
nymea-app/ruletemplates/thermostattemplates.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -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'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'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'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'm home</source>
|
||||
<translation>Setze Temperatur während ich zuhause bin</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
||||
@ -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'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'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'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'm home</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
||||
@ -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't be able to connect to %1:core systems remotely any more. However, you can come back any time, we'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'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'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'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'm home</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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";
|
||||
}
|
||||
|
||||
@ -91,7 +91,6 @@ Item {
|
||||
|
||||
Label {
|
||||
text: infoPane.text
|
||||
visible: infoPane.alertState
|
||||
font.pixelSize: app.smallFont
|
||||
color: "white"
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
111
nymea-app/ui/devicepages/DoorbellDevicePage.qml
Normal file
111
nymea-app/ui/devicepages/DoorbellDevicePage.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
37
nymea-app/ui/magic/NewMagicPage.qml
Normal file
37
nymea-app/ui/magic/NewMagicPage.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -43,6 +43,9 @@ Page {
|
||||
engine: _engine
|
||||
groupByInterface: true
|
||||
nameFilter: filterInput.shown ? filterInput.text : ""
|
||||
Component.onCompleted: {
|
||||
print("showing devices for interfaces", devicesProxy.shownInterfaces)
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
@ -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]})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user