more work on states

pull/1/head
Michael Zanetti 2018-03-09 09:30:09 +01:00
parent 5a32fe57de
commit c382d13e70
39 changed files with 1081 additions and 149 deletions

View File

@ -133,7 +133,6 @@ void DeviceManager::getSupportedDevicesResponse(const QVariantMap &params)
QVariantList deviceClassList = params.value("params").toMap().value("deviceClasses").toList();
foreach (QVariant deviceClassVariant, deviceClassList) {
DeviceClass *deviceClass = JsonTypes::unpackDeviceClass(deviceClassVariant.toMap(), Engine::instance()->deviceManager()->deviceClasses());
qDebug() << "Server has device class:" << deviceClass->name() << deviceClass->id();
m_deviceClasses->addDeviceClass(deviceClass);
}
}
@ -280,7 +279,7 @@ void DeviceManager::addDiscoveredDevice(const QUuid &deviceClassId, const QUuid
params.insert("deviceClassId", deviceClassId.toString());
params.insert("name", name);
params.insert("deviceDescriptorId", deviceDescriptorId.toString());
m_jsonClient->sendCommand("Devices.AddConfiguredDevice", params);
m_jsonClient->sendCommand("Devices.AddConfiguredDevice", params, this, "addDeviceResponse");
}
void DeviceManager::pairDevice(const QUuid &deviceClassId, const QUuid &deviceDescriptorId, const QString &name)

View File

@ -148,7 +148,7 @@ void UpnpDiscovery::readData()
if (key.contains("Server") || key.contains("SERVER")) {
if (value.contains("guh")) {
if (value.contains("nymea")) {
qDebug() << " --> " << key << value;
isGuh = true;
}
@ -160,6 +160,10 @@ void UpnpDiscovery::readData()
}
}
if (isGuh) {
qDebug() << "Found guh device:" << location;
}
if (!m_foundDevices.contains(location) && isGuh) {
m_foundDevices.append(location);
DiscoveryDevice discoveryDevice;
@ -201,7 +205,7 @@ void UpnpDiscovery::networkReplyFinished(QNetworkReply *reply)
}
if (xml.isStartElement()) {
if (xml.name().toString() == "guhRpcURL") {
if (xml.name().toString() == "nymeaRpcURL") {
discoveryDevice.setGuhRpcUrl(xml.readElementText());
}
}

View File

@ -31,7 +31,7 @@ bool ZeroconfDiscovery::discovering() const
#ifdef WITH_AVAHI
void ZeroconfDiscovery::serviceEntryAdded(const AvahiServiceEntry &entry)
{
if (!entry.name().startsWith("guhIO") || entry.serviceType() != "_jsonrpc._tcp") {
if (!entry.name().startsWith("nymea") || entry.serviceType() != "_jsonrpc._tcp") {
return;
}
qDebug() << "avahi service entry added" << entry.name() << entry.hostAddress() << entry.port() << entry.txt() << entry.serviceType();
@ -57,7 +57,7 @@ void ZeroconfDiscovery::serviceEntryAdded(const AvahiServiceEntry &entry)
dev.setHostAddress(entry.hostAddress());
dev.setPort(entry.port());
dev.setFriendlyName(entry.hostName());
dev.setGuhRpcUrl(QString("%1://%2:%3").arg(sslEnabled ? "guhs" : "guh").arg(entry.hostAddress().toString()).arg(entry.port()));
dev.setGuhRpcUrl(QString("%1://%2:%3").arg(sslEnabled ? "nymeas" : "nymea").arg(entry.hostAddress().toString()).arg(entry.port()));
m_discoveryModel->addDevice(dev);
// DiscoveryDevice *dev = new DiscoveryDevice();

View File

@ -65,7 +65,7 @@ QString GuhConnection::url() const
void GuhConnection::sendData(const QByteArray &data)
{
if (connected()) {
qDebug() << "sending data:" << data;
// qDebug() << "sending data:" << data;
m_currentInterface->sendData(data);
} else {
qWarning() << "Not connected. Cannot send.";

View File

@ -31,6 +31,9 @@
#include "types/eventdescriptors.h"
#include "types/ruleactionparam.h"
#include "types/ruleactionparams.h"
#include "types/stateevaluator.h"
#include "types/stateevaluators.h"
#include "types/statedescriptor.h"
#include <QMetaEnum>
@ -223,56 +226,74 @@ QVariantMap JsonTypes::packRule(Rule *rule)
ret.insert("name", rule->name());
ret.insert("enabled", rule->enabled());
if (rule->ruleActions()->rowCount() > 0) {
QVariantList actions;
for (int i = 0; i < rule->ruleActions()->rowCount(); i++) {
QVariantMap ruleAction;
ruleAction.insert("actionTypeId", rule->ruleActions()->get(i)->actionTypeId());
ruleAction.insert("deviceId", rule->ruleActions()->get(i)->deviceId());
if (rule->ruleActions()->get(i)->ruleActionParams()->rowCount() > 0) {
QVariantList ruleActionParams;
for (int j = 0; j < rule->ruleActions()->get(i)->ruleActionParams()->rowCount(); j++) {
QVariantMap ruleActionParam;
ruleActionParam.insert("paramTypeId", rule->ruleActions()->get(i)->ruleActionParams()->get(j)->paramTypeId());
ruleActionParam.insert("value", rule->ruleActions()->get(i)->ruleActionParams()->get(j)->value());
ruleActionParams.append(ruleActionParam);
}
ruleAction.insert("ruleActionParams", ruleActionParams);
}
actions.append(ruleAction);
}
ret.insert("actions", actions);
if (rule->actions()->rowCount() > 0) {
ret.insert("actions", packRuleActions(rule->actions()));
}
if (rule->exitActions()->rowCount() > 0) {
ret.insert("exitActions", packRuleActions(rule->exitActions()));
}
if (rule->eventDescriptors()->rowCount() > 0) {
QVariantList eventDescriptors;
for (int i = 0; i < rule->eventDescriptors()->rowCount(); i++) {
QVariantMap eventDescriptorMap;
EventDescriptor* eventDescriptor = rule->eventDescriptors()->get(i);
if (!eventDescriptor->deviceId().isNull() && !eventDescriptor->eventTypeId().isNull()) {
eventDescriptorMap.insert("eventTypeId", eventDescriptor->eventTypeId());
eventDescriptorMap.insert("deviceId", eventDescriptor->deviceId());
} else {
eventDescriptorMap.insert("interface", eventDescriptor->interfaceName());
eventDescriptorMap.insert("interfaceEvent", eventDescriptor->interfaceEvent());
}
if (eventDescriptor->paramDescriptors()->rowCount() > 0) {
QVariantList paramDescriptors;
for (int j = 0; j < rule->eventDescriptors()->get(i)->paramDescriptors()->rowCount(); j++) {
QVariantMap paramDescriptor;
paramDescriptor.insert("paramTypeId", rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->paramTypeId());
paramDescriptor.insert("value", rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->value());
QMetaEnum operatorEnum = QMetaEnum::fromType<ParamDescriptor::ValueOperator>();
paramDescriptor.insert("operator", operatorEnum.valueToKey(rule->eventDescriptors()->get(i)->paramDescriptors()->get(j)->operatorType()));
paramDescriptors.append(paramDescriptor);
}
eventDescriptorMap.insert("paramDescriptors", paramDescriptors);
}
eventDescriptors.append(eventDescriptorMap);
}
ret.insert("eventDescriptors", eventDescriptors);
ret.insert("eventDescriptors", packEventDescriptors(rule->eventDescriptors()));
}
if (rule->stateEvaluator()) {
ret.insert("stateEvaluator", packStateEvaluator(rule->stateEvaluator()));
}
return ret;
}
QVariantList JsonTypes::packRuleActions(RuleActions *ruleActions)
{
QVariantList ret;
for (int i = 0; i < ruleActions->rowCount(); i++) {
QVariantMap ruleAction;
ruleAction.insert("actionTypeId", ruleActions->get(i)->actionTypeId());
ruleAction.insert("deviceId", ruleActions->get(i)->deviceId());
if (ruleActions->get(i)->ruleActionParams()->rowCount() > 0) {
QVariantList ruleActionParams;
for (int j = 0; j < ruleActions->get(i)->ruleActionParams()->rowCount(); j++) {
QVariantMap ruleActionParam;
ruleActionParam.insert("paramTypeId", ruleActions->get(i)->ruleActionParams()->get(j)->paramTypeId());
ruleActionParam.insert("value", ruleActions->get(i)->ruleActionParams()->get(j)->value());
ruleActionParams.append(ruleActionParam);
}
ruleAction.insert("ruleActionParams", ruleActionParams);
}
ret.append(ruleAction);
}
return ret;
}
QVariantList JsonTypes::packEventDescriptors(EventDescriptors *eventDescriptors)
{
QVariantList ret;
for (int i = 0; i < eventDescriptors->rowCount(); i++) {
QVariantMap eventDescriptorMap;
EventDescriptor* eventDescriptor = eventDescriptors->get(i);
if (!eventDescriptor->deviceId().isNull() && !eventDescriptor->eventTypeId().isNull()) {
eventDescriptorMap.insert("eventTypeId", eventDescriptor->eventTypeId());
eventDescriptorMap.insert("deviceId", eventDescriptor->deviceId());
} else {
eventDescriptorMap.insert("interface", eventDescriptor->interfaceName());
eventDescriptorMap.insert("interfaceEvent", eventDescriptor->interfaceEvent());
}
if (eventDescriptor->paramDescriptors()->rowCount() > 0) {
QVariantList paramDescriptors;
for (int j = 0; j < eventDescriptor->paramDescriptors()->rowCount(); j++) {
QVariantMap paramDescriptor;
paramDescriptor.insert("paramTypeId", eventDescriptor->paramDescriptors()->get(j)->paramTypeId());
paramDescriptor.insert("value", eventDescriptor->paramDescriptors()->get(j)->value());
QMetaEnum operatorEnum = QMetaEnum::fromType<ParamDescriptor::ValueOperator>();
paramDescriptor.insert("operator", operatorEnum.valueToKey(eventDescriptor->paramDescriptors()->get(j)->operatorType()));
paramDescriptors.append(paramDescriptor);
}
eventDescriptorMap.insert("paramDescriptors", paramDescriptors);
}
ret.append(eventDescriptorMap);
}
return ret;
}
@ -284,6 +305,26 @@ QVariantMap JsonTypes::packParam(Param *param)
return ret;
}
QVariantMap JsonTypes::packStateEvaluator(StateEvaluator *stateEvaluator)
{
QVariantMap ret;
QMetaEnum stateOperatorEnum = QMetaEnum::fromType<StateEvaluator::StateOperator>();
ret.insert("operator", stateOperatorEnum.valueToKey(stateEvaluator->stateOperator()));
QVariantMap stateDescriptor;
stateDescriptor.insert("deviceId", stateEvaluator->stateDescriptor()->deviceId());
QMetaEnum valueOperatorEnum = QMetaEnum::fromType<StateDescriptor::ValueOperator>();
stateDescriptor.insert("operator", valueOperatorEnum.valueToKeys(stateEvaluator->stateDescriptor()->valueOperator()));
stateDescriptor.insert("stateTypeId", stateEvaluator->stateDescriptor()->stateTypeId());
stateDescriptor.insert("value", stateEvaluator->stateDescriptor()->value());
ret.insert("stateDescriptor", stateDescriptor);
QVariantList childEvaluators;
for (int i = 0; i < stateEvaluator->childEvaluators()->rowCount(); i++) {
childEvaluators.append(packStateEvaluator(stateEvaluator->childEvaluators()->get(i)));
}
ret.insert("childEvaluators", childEvaluators);
return ret;
}
DeviceClass::SetupMethod JsonTypes::stringToSetupMethod(const QString &setupMethodString)
{
if (setupMethodString == "SetupMethodJustAdd") {

View File

@ -27,17 +27,22 @@
#include <QUuid>
#include "types/types.h"
#include "types/device.h"
#include "types/plugin.h"
#include "types/deviceclass.h"
#include "types/paramtype.h"
#include "types/statetype.h"
#include "types/state.h"
#include "types/eventtype.h"
#include "types/actiontype.h"
class Plugin;
class Vendor;
class StateType;
class EventType;
class ActionType;
class ParamType;
class Device;
class Param;
class Rule;
class StateEvaluator;
class RuleActions;
class EventDescriptors;
class JsonTypes : public QObject
{
@ -56,7 +61,10 @@ public:
static Device *unpackDevice(const QVariantMap &deviceMap, QObject *parent);
static QVariantMap packRule(Rule* rule);
static QVariantList packRuleActions(RuleActions* ruleActions);
static QVariantList packEventDescriptors(EventDescriptors* eventDescriptors);
static QVariantMap packParam(Param *param);
static QVariantMap packStateEvaluator(StateEvaluator* stateEvaluator);
private:
static DeviceClass::SetupMethod stringToSetupMethod(const QString &setupMethodString);
static QList<DeviceClass::BasicTag> stringListToBasicTags(const QStringList &basicTagsStringList);

View File

@ -44,6 +44,9 @@
#include "types/rule.h"
#include "types/interfaces.h"
#include "types/interface.h"
#include "types/statedescriptor.h"
#include "types/stateevaluator.h"
#include "types/stateevaluators.h"
#include "models/logsmodel.h"
#include "models/valuelogsproxymodel.h"
#include "basicconfiguration.h"
@ -131,6 +134,9 @@ int main(int argc, char *argv[])
qmlRegisterType<Param>(uri, 1, 0, "Param");
qmlRegisterUncreatableType<ParamDescriptor>(uri, 1, 0, "ParamDescriptor", "Uncreatable");
qmlRegisterUncreatableType<ParamDescriptors>(uri, 1, 0, "ParamDescriptors", "Uncreatable");
qmlRegisterUncreatableType<StateDescriptor>(uri, 1, 0, "StateDescriptor", "Uncreatable");
qmlRegisterUncreatableType<StateEvaluator>(uri, 1, 0, "StateEvaluator", "Uncreatable");
qmlRegisterUncreatableType<StateEvaluators>(uri, 1, 0, "StateEvaluators", "Uncreatable");
qmlRegisterUncreatableType<Interface>(uri, 1, 0, "Interface", "Uncreatable");
qmlRegisterSingletonType<Interfaces>(uri, 1, 0, "Interfaces", interfacesModel_provider);

View File

@ -155,7 +155,7 @@ void LogsModel::update()
void LogsModel::logsReply(const QVariantMap &data)
{
qDebug() << "logs reply";
qDebug() << "logs reply" << data;
m_busy = false;
emit busyChanged();
beginResetModel();
@ -167,12 +167,12 @@ void LogsModel::logsReply(const QVariantMap &data)
QVariantMap entryMap = logEntryVariant.toMap();
QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(entryMap.value("timestamp").toLongLong());
QString deviceId = entryMap.value("deviceId").toString();
QVariant value = entryMap.value("value");
QString typeId = entryMap.value("typeId").toString();
QMetaEnum sourceEnum = QMetaEnum::fromType<LogEntry::LoggingSource>();
LogEntry::LoggingSource loggingSource = (LogEntry::LoggingSource)sourceEnum.keyToValue(entryMap.value("source").toByteArray());
QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType<LogEntry::LoggingEventType>();
LogEntry::LoggingEventType loggingEventType = (LogEntry::LoggingEventType)loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray());
QVariant value = loggingEventType == LogEntry::LoggingEventTypeActiveChange ? entryMap.value("active").toBool() : entryMap.value("value");
LogEntry *entry = new LogEntry(timeStamp, value, deviceId, typeId, loggingSource, loggingEventType, this);
m_list.append(entry);
}
@ -191,12 +191,12 @@ void LogsModel::newLogEntryReceived(const QVariantMap &data)
QVariantMap entryMap = data;
QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(entryMap.value("timestamp").toLongLong());
QString deviceId = entryMap.value("deviceId").toString();
QVariant value = entryMap.value("value");
QString typeId = entryMap.value("typeId").toString();
QMetaEnum sourceEnum = QMetaEnum::fromType<LogEntry::LoggingSource>();
LogEntry::LoggingSource loggingSource = (LogEntry::LoggingSource)sourceEnum.keyToValue(entryMap.value("source").toByteArray());
QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType<LogEntry::LoggingEventType>();
LogEntry::LoggingEventType loggingEventType = (LogEntry::LoggingEventType)loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray());
QVariant value = loggingEventType == LogEntry::LoggingEventTypeActiveChange ? entryMap.value("active").toBool() : entryMap.value("value");
LogEntry *entry = new LogEntry(timeStamp, value, deviceId, typeId, loggingSource, loggingEventType, this);
m_list.append(entry);
endInsertRows();

View File

@ -66,8 +66,17 @@ bool RulesFilterModel::filterAcceptsRow(int source_row, const QModelIndex &sourc
found = true;
}
if (!found) {
for (int i = 0; i < rule->ruleActions()->rowCount(); i++) {
RuleAction *ra = rule->ruleActions()->get(i);
for (int i = 0; i < rule->actions()->rowCount(); i++) {
RuleAction *ra = rule->actions()->get(i);
if (ra->deviceId() == m_filterDeviceId) {
found = true;
break;
}
}
}
if (!found) {
for (int i = 0; i < rule->exitActions()->rowCount(); i++) {
RuleAction *ra = rule->exitActions()->get(i);
if (ra->deviceId() == m_filterDeviceId) {
found = true;
break;

View File

@ -134,5 +134,11 @@
<file>ui/fonts/Ubuntu-R.ttf</file>
<file>ui/fonts/Ubuntu-RI.ttf</file>
<file>ui/components/InterfacesModels.qml</file>
<file>ui/magic/StateEvaluatorDelegate.qml</file>
<file>ui/magic/EditStateEvaluatorPage.qml</file>
<file>ui/actiondelegates-ng/ActionDelegate.qml</file>
<file>ui/magic/SimpleStateEvaluatorDelegate.qml</file>
<file>ui/magic/SelectStateDescriptorParamsPage.qml</file>
<file>ui/magic/SelectStateDescriptorPage.qml</file>
</qresource>
</RCC>

View File

@ -10,6 +10,7 @@
#include "types/ruleactionparams.h"
#include "types/ruleactionparam.h"
#include "types/stateevaluator.h"
#include "types/stateevaluators.h"
#include "types/statedescriptor.h"
#include <QMetaEnum>
@ -68,6 +69,7 @@ void RuleManager::removeRule(const QUuid &ruleId)
void RuleManager::editRule(Rule *rule)
{
QVariantMap params = JsonTypes::packRule(rule);
qWarning() << "Packed rule:" << params;
m_jsonClient->sendCommand("Rules.EditRule", params, this, "onEditRuleReply");
}
@ -97,7 +99,8 @@ void RuleManager::handleRulesNotification(const QVariantMap &params)
}
m_rules->remove(ruleId);
m_rules->insert(parseRule(ruleMap));
} else if (params.value("notification").toString() == "Rules.RuleActiveChanged") {
m_rules->getRule(params.value("params").toMap().value("ruleId").toUuid())->setActive(params.value("params").toMap().value("active").toBool());
} else {
qWarning() << "Unhandled rule notification" << params;
}
@ -113,10 +116,12 @@ void RuleManager::getRulesReply(const QVariantMap &params)
QUuid ruleId = ruleDescriptionVariant.toMap().value("id").toUuid();
QString name = ruleDescriptionVariant.toMap().value("name").toString();
bool enabled = ruleDescriptionVariant.toMap().value("enabled").toBool();
bool active = ruleDescriptionVariant.toMap().value("active").toBool();
Rule *rule = new Rule(ruleId, m_rules);
rule->setName(name);
rule->setEnabled(enabled);
rule->setActive(active);
m_rules->insert(rule);
QVariantMap requestParams;
@ -136,7 +141,8 @@ void RuleManager::getRuleDetailsReply(const QVariantMap &params)
qDebug() << "got rule details for rule" << ruleMap;
parseEventDescriptors(ruleMap.value("eventDescriptors").toList(), rule);
parseRuleActions(ruleMap.value("actions").toList(), rule);
parseStateEvaluator(ruleMap.value("stateEvaluator").toMap());
parseRuleExitActions(ruleMap.value("exitActions").toList(), rule);
rule->setStateEvaluator(parseStateEvaluator(ruleMap.value("stateEvaluator").toMap()));
}
void RuleManager::onAddRuleReply(const QVariantMap &params)
@ -167,9 +173,9 @@ Rule *RuleManager::parseRule(const QVariantMap &ruleMap)
rule->setEnabled(enabled);
rule->setActive(active);
parseEventDescriptors(ruleMap.value("eventDescriptors").toList(), rule);
StateEvaluator* stateEvaluator = parseStateEvaluator(ruleMap.value("stateEvaluator").toMap());
stateEvaluator->setParent(rule);
parseRuleActions(ruleMap.value("actions").toList(), rule);
parseRuleExitActions(ruleMap.value("exitActions").toList(), rule);
rule->setStateEvaluator(parseStateEvaluator(ruleMap.value("stateEvaluator").toMap()));
return rule;
}
@ -193,28 +199,21 @@ void RuleManager::parseEventDescriptors(const QVariantList &eventDescriptorList,
StateEvaluator *RuleManager::parseStateEvaluator(const QVariantMap &stateEvaluatorMap)
{
qDebug() << "bla" << stateEvaluatorMap;
StateEvaluator *stateEvaluator = new StateEvaluator(this);
if (stateEvaluatorMap.contains("stateDescriptor")) {
QVariantMap sdMap = stateEvaluatorMap.value("sateDescriptor").toMap();
QString operatorString = sdMap.value("stateOperator").toString();
StateDescriptor::ValueOperator op;
if (operatorString == "ValueOperatorEquals") {
op = StateDescriptor::ValueOperatorEquals;
} else if (operatorString == "ValueOperatorNotEquals") {
op = StateDescriptor::ValueOperatorNotEquals;
} else if (operatorString == "ValueOperatorLess") {
op = StateDescriptor::ValueOperatorLess;
} else if (operatorString == "ValueOperatorGreater") {
op = StateDescriptor::ValueOperatorGreater;
} else if (operatorString == "ValueOperatorLessOrEqual") {
op = StateDescriptor::ValueOperatorLessOrEqual;
} else if (operatorString == "ValueOperatorGreaterOrEqual") {
op = StateDescriptor::ValueOperatorGreaterOrEqual;
}
QVariantMap sdMap = stateEvaluatorMap.value("stateDescriptor").toMap();
QMetaEnum operatorEnum = QMetaEnum::fromType<StateDescriptor::ValueOperator>();
StateDescriptor::ValueOperator op = (StateDescriptor::ValueOperator)operatorEnum.keyToValue(sdMap.value("operator").toByteArray());
StateDescriptor *sd = new StateDescriptor(sdMap.value("deviceId").toUuid(), op, sdMap.value("stateTypeId").toUuid(), sdMap.value("value"), stateEvaluator);
stateEvaluator->setStateDescriptor(sd);
}
foreach (const QVariant &childEvaluatorVariant, stateEvaluatorMap.value("childEvaluators").toList()) {
stateEvaluator->childEvaluators()->addStateEvaluator(parseStateEvaluator(childEvaluatorVariant.toMap()));
}
QMetaEnum operatorEnum = QMetaEnum::fromType<StateEvaluator::StateOperator>();
stateEvaluator->setStateOperator((StateEvaluator::StateOperator)operatorEnum.keyToValue(stateEvaluatorMap.value("operator").toByteArray()));
return stateEvaluator;
}
@ -230,6 +229,22 @@ void RuleManager::parseRuleActions(const QVariantList &ruleActions, Rule *rule)
param->setValue(ruleActionParamVariant.toMap().value("value"));
ruleAction->ruleActionParams()->addRuleActionParam(param);
}
rule->ruleActions()->addRuleAction(ruleAction);
rule->actions()->addRuleAction(ruleAction);
}
}
void RuleManager::parseRuleExitActions(const QVariantList &ruleActions, Rule *rule)
{
foreach (const QVariant &ruleActionVariant, ruleActions) {
RuleAction *ruleAction = new RuleAction();
ruleAction->setDeviceId(ruleActionVariant.toMap().value("deviceId").toUuid());
ruleAction->setActionTypeId(ruleActionVariant.toMap().value("actionTypeId").toUuid());
foreach (const QVariant &ruleActionParamVariant, ruleActionVariant.toMap().value("ruleActionParams").toList()) {
RuleActionParam *param = new RuleActionParam();
param->setParamTypeId(ruleActionParamVariant.toMap().value("paramTypeId").toUuid());
param->setValue(ruleActionParamVariant.toMap().value("value"));
ruleAction->ruleActionParams()->addRuleActionParam(param);
}
rule->exitActions()->addRuleAction(ruleAction);
}
}

View File

@ -44,6 +44,7 @@ private:
void parseEventDescriptors(const QVariantList &eventDescriptorList, Rule *rule);
StateEvaluator* parseStateEvaluator(const QVariantMap &stateEvaluatorMap);
void parseRuleActions(const QVariantList &ruleActions, Rule *rule);
void parseRuleExitActions(const QVariantList &ruleActions, Rule *rule);
signals:
void addRuleReply(const QString &ruleError);

View File

@ -16,7 +16,7 @@ TcpSocketInterface::TcpSocketInterface(QObject *parent) : GuhInterface(parent)
QStringList TcpSocketInterface::supportedSchemes() const
{
return {"guh", "guhs"};
return {"nymea", "nymeas"};
}
void TcpSocketInterface::sendData(const QByteArray &data)
@ -31,7 +31,7 @@ void TcpSocketInterface::ignoreSslErrors(const QList<QSslError> &errors)
void TcpSocketInterface::onConnected()
{
if (m_url.scheme() == "guh") {
if (m_url.scheme() == "nymea") {
qDebug() << "TCP socket connected";
emit connected();
}
@ -46,10 +46,10 @@ void TcpSocketInterface::onEncrypted()
void TcpSocketInterface::connect(const QUrl &url)
{
m_url = url;
if (url.scheme() == "guhs") {
if (url.scheme() == "nymeas") {
qDebug() << "connecting to" << url.host() << url.port();
m_socket.connectToHostEncrypted(url.host(), url.port());
} else if (url.scheme() == "guh") {
} else if (url.scheme() == "nymea") {
m_socket.connectToHost(url.host(), url.port());
} else {
qWarning() << "Unsupported scheme";

View File

@ -130,11 +130,26 @@ Page {
Component {
id: connectingPage
Page {
Label {
ColumnLayout {
anchors.centerIn: parent
width: parent.width - app.margins * 2
text: "Connecting to your guh box..."
font.pixelSize: app.largeFont
spacing: app.margins
Label {
text: qsTr("Connecting to your guh box...")
wrapMode: Text.WordWrap
font.pixelSize: app.largeFont
Layout.fillWidth: true
}
Button {
text: "Cancel"
Layout.fillWidth: true
onClicked: {
Engine.connection.disconnect()
pageStack.pop();
}
}
}
}
}

View File

@ -0,0 +1,287 @@
import QtQuick 2.8
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.1
import Guh 1.0
import "../components"
ItemDelegate {
id: root
property var actionType: null
property var actionState: null
signal executeAction(var params)
contentItem: ColumnLayout {
RowLayout {
Label {
Layout.fillWidth: true
text: root.actionType.displayName
elide: Text.ElideRight
}
Loader {
id: loader
Layout.fillWidth: sourceComponent == textFieldComponent
sourceComponent: {
if (root.actionType.paramTypes.count !== 1) {
return buttonComponent
}
var paramType = root.actionType.paramTypes.get(0);
switch (paramType.type.toLowerCase()) {
case "bool":
return boolComponent;
case "int":
return stringComponent;
case "string":
case "qstring":
if (paramType.allowedValues.length > 0) {
return comboBoxComponent;
}
return textFieldComponent;
case "color":
return colorPreviewComponent;
}
console.warn("Param Delegate: Fallback to stringComponent", paramType.name, paramType.type)
return stringComponent;
}
}
Binding {
target: loader.item
when: loader.item
property: "paramType"
value: root.actionType.paramTypes.get(0)
}
Binding {
target: loader.item
when: loader.item
property: "value"
value: root.actionState
}
}
Repeater {
id: paramRepeater
model: root.actionType.paramTypes
delegate: Loader {
id: bottomLoader
property var paramType: root.actionType.paramTypes.get(index)
Layout.fillWidth: true
sourceComponent: {
switch (paramType.type.toLowerCase()) {
case "int":
case "double":
if (paramType.minValue != undefined && paramType.maxValue != undefined) {
return sliderComponent
}
break;
case "color":
return colorPickerComponent
case "string":
return paramType.allowedValues.length === 0 ? textFieldComponent : null
}
return null;
}
Binding {
target: bottomLoader.item
when: bottomLoader.item
property: "paramType"
value: bottomLoader.paramType
}
Binding {
target: bottomLoader.item
when: bottomLoader.item && root.actionState
property: "value"
value: root.actionState
}
}
}
}
Component {
id: stringComponent
Label {
property var paramType: null
property var value: null
text: {
switch (paramType.type.toLowerCase()) {
case "int":
return Math.round(value);
}
return value;
}
}
}
Component {
id: boolComponent
Switch {
checked: root.actionState === true
onClicked: {
var params = [];
var param1 = new Object();
param1["paramTypeId"] = root.actionType.paramTypes.get(0).id;
param1["value"] = checked;
params.push(param1)
root.executeAction(params)
}
}
}
Component {
id: sliderComponent
RowLayout {
id: sliderRow
spacing: app.margins
property var paramType: null
property var value: null
Label {
text: sliderRow.paramType.minValue
}
Slider {
Layout.fillWidth: true
from: sliderRow.paramType.minValue
to: sliderRow.paramType.maxValue
value: sliderRow.value
stepSize: {
switch (sliderRow.paramType.type) {
case "Int":
return 1;
}
return 0.01;
}
onValueChanged: {
if (pressed) {
var params = [];
var param1 = new Object();
param1["paramTypeId"] = sliderRow.paramType.id;
param1["value"] = value;
params.push(param1)
root.executeAction(params)
}
}
}
Label {
text: sliderRow.paramType.maxValue
}
}
}
Component {
id: textFieldComponent
RowLayout {
property alias value: textField.text
property var paramType: null
spacing: app.margins
Label {
text: paramType.displayName
}
TextField {
id: textField
Layout.fillWidth: true
}
}
}
Component {
id: comboBoxComponent
ComboBox {
id: box
model: paramType.allowedValues
currentIndex: paramType.allowedValues.indexOf(value)
property var paramType: null
property var value: null
onActivated: {
value = paramType.allowedValues[index]
var params = [];
var param1 = new Object();
param1["paramTypeId"] = paramType.id;
param1["value"] = currentText;
params.push(param1)
root.executeAction(params)
}
}
}
Component {
id: colorPickerComponent
ColorPicker {
id: colorPicker
implicitHeight: 200
// color: root.param.value
Binding {
target: colorPicker
property: "color"
value: root.actionState
when: !colorPicker.pressed
}
property var lastSentTime: new Date()
onColorChanged: {
var currentTime = new Date();
if (pressed && currentTime - lastSentTime > 200) {
var params = [];
var param1 = new Object();
param1["paramTypeId"] = paramType.id;
param1["value"] = color;
params.push(param1)
root.executeAction(params)
}
}
touchDelegate: Rectangle {
height: 15
width: height
radius: height / 2
color: Material.accent
Rectangle {
color: colorPicker.hovered || colorPicker.pressed ? "#11000000" : "transparent"
anchors.centerIn: parent
height: 30
width: height
radius: width / 2
Behavior on color { ColorAnimation { duration: 200 } }
}
}
}
}
Component {
id: colorPreviewComponent
Rectangle {
property var paramType: null
property var value: null
implicitHeight: app.mediumFont
implicitWidth: implicitHeight
color: value
radius: width / 4
}
}
Component {
id: buttonComponent
Button {
// just to suppress some warnings
property var paramType: null
property var value: null
text: "Do it"
onClicked: {
var params = [];
for (var i = 0; i < root.actionType.paramTypes.count; i++) {
var param = new Object();
param["paramTypeId"] = root.actionType.paramTypes.get(i).id;
param["value"] = paramRepeater.itemAt(i).item.value;
params.push(param)
}
root.executeAction(params)
}
}
}
}

View File

@ -25,7 +25,10 @@ Page {
return qsTr("All my things")
}
onBackPressed: pageStack.pop()
onBackPressed: {
print("popping")
pageStack.pop()
}
}
function enterPage(index, replace) {

View File

@ -61,6 +61,7 @@ Page {
Label {
Layout.fillWidth: true
text: model.name
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
Slider {

View File

@ -9,7 +9,10 @@ DevicePageBase {
header: GuhHeader {
text: device.name
onBackPressed: pageStack.pop()
onBackPressed: {
print("popping")
pageStack.pop()
}
HeaderButton {
imageSource: "../images/info.svg"
@ -34,11 +37,11 @@ DevicePageBase {
model: RulesFilterModel {
id: rulesFilterModel
rules: Engine.ruleManager.rules
filterEventDeviceId: root.device.id
filterDeviceId: root.device.id
}
delegate: SwipeDelegate {
width: parent.width
property var ruleActions: rulesFilterModel.get(index).ruleActions
property var ruleActions: rulesFilterModel.get(index).actions
property var ruleAction: ruleActions.count == 1 ? ruleActions.get(0) : null
property var ruleActionType: ruleAction ? ruleActionDeviceClass.actionTypes.getActionType(ruleAction.actionTypeId) : null
property var ruleActionDevice: ruleAction ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null

View File

@ -1,9 +1,9 @@
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Material 2.1
import Guh 1.0
import "../components"
import "../actiondelegates"
DevicePageBase {
id: root
@ -116,23 +116,55 @@ DevicePageBase {
}
ActionDelegateColor {
ColorPicker {
id: colorPicker
Layout.fillWidth: true
Layout.fillHeight: true
actionType: root.deviceClass.actionTypes.findByName("color")
actionState: actionType ? root.device.states.getState(actionType.id).value : null
Layout.margins: app.margins
property var actionType: root.deviceClass.actionTypes.findByName("color")
property var actionState: actionType ? root.device.states.getState(actionType.id).value : null
visible: root.deviceClass.interfaces.indexOf("colorlight") >= 0
onExecuteAction: {
Engine.deviceManager.executeAction(root.device.id, actionType.id, params)
color: actionState ? actionState : "white"
touchDelegate: Rectangle {
height: 15
width: height
radius: height / 2
color: Material.accent
Rectangle {
color: colorPicker.hovered || colorPicker.pressed ? "#11000000" : "transparent"
anchors.centerIn: parent
height: 30
width: height
radius: width / 2
Behavior on color {
ColorAnimation {
duration: 200
}
}
}
}
property var lastSentTime: new Date()
onColorChanged: {
var currentTime = new Date();
if (pressed && currentTime - lastSentTime > 200) {
var params = [];
var param1 = new Object();
param1["paramTypeId"] = actionType.paramTypes.get(0).id;
param1["value"] = color;
params.push(param1)
Engine.deviceManager.executeAction(root.device.id, actionType.id, params)
lastSentTime = currentTime
}
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: 0
}
}
}

View File

@ -103,6 +103,7 @@ DevicePageBase {
print("have actionType param:", actionType.paramTypes.get(i).name, actionType.paramTypes.get(i).type)
}
return Qt.resolvedUrl("../actiondelegates-ng/ActionDelegate.qml");
var delegate = "ActionDelegateFallback.qml";
if (actionType.paramTypes.count === 0) {
delegate = "ActionDelegateNoParams.qml";
@ -117,7 +118,10 @@ DevicePageBase {
} else if (paramType.type === "String" && paramType.allowedValues.length > 0) {
delegate = "ActionDelegateStringFromStringList.qml";
}
} else {
}
return Qt.resolvedUrl("../actiondelegates/" + delegate);
}
@ -136,7 +140,7 @@ DevicePageBase {
Connections {
target: delegateLoader.item ? delegateLoader.item : null
onExecuteAction: {
delegateLoader.commandId = Engine.deviceManager.executeAction(root.device.id, model.id, params)
Engine.deviceManager.executeAction(root.device.id, model.id, params)
}
}
Connections {

View File

@ -13,6 +13,11 @@ Page {
onAccept: busyOverlay.opacity = 1
readonly property bool isStateBased: rule.eventDescriptors.count === 0
readonly property bool actionsVisible: rule.eventDescriptors.count > 0 || rule.stateEvaluator !== null
readonly property bool exitActionsVisible: actionsVisible && isStateBased
readonly property bool hasExitActions: rule.exitActions.count > 0
function addEventDescriptor() {
var eventDescriptor = root.rule.eventDescriptors.createNewEventDescriptor();
var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"));
@ -36,27 +41,51 @@ Page {
})
}
function addRuleAction() {
var ruleAction = root.rule.ruleActions.createNewRuleAction();
function editStateEvaluator() {
print("opening page", root.rule.stateEvaluator)
var page = pageStack.push(Qt.resolvedUrl("EditStateEvaluatorPage.qml"), { stateEvaluator: root.rule.stateEvaluator })
}
function addAction() {
var ruleAction = root.rule.actions.createNewRuleAction();
var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"));
page.onBackPressed.connect(function() { pageStack.pop() })
page.onThingSelected.connect(function(device) {
print("thing selected", device.name, device.id)
ruleAction.deviceId = device.id;
selectRuleActionData(ruleAction)
selectRuleActionData(root.rule.actions, ruleAction)
})
page.onInterfaceSelected.connect(function(interfaceName) {
print("interface selected", interfaceName)
ruleAction.interfaceName = interfaceName;
selectRuleActionData(ruleAction)
selectRuleActionData(root.rule.actions, ruleAction)
})
}
function selectRuleActionData(ruleAction) {
function addExitAction() {
var ruleAction = root.rule.exitActions.createNewRuleAction();
var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"));
page.onBackPressed.connect(function() { pageStack.pop() })
page.onThingSelected.connect(function(device) {
print("thing selected", device.name, device.id)
ruleAction.deviceId = device.id;
selectRuleActionData(root.rule.exitActions, ruleAction)
})
page.onInterfaceSelected.connect(function(interfaceName) {
print("interface selected", interfaceName)
ruleAction.interfaceName = interfaceName;
selectRuleActionData(root.rule.exitActions, ruleAction)
})
}
function selectRuleActionData(ruleActions, ruleAction) {
print("opening with ruleAction", ruleAction)
var ruleActionPage = pageStack.push(Qt.resolvedUrl("SelectRuleActionPage.qml"), {text: "Select action", ruleAction: ruleAction });
ruleActionPage.onBackPressed.connect(function() {
ruleAction.destroy();
pageStack.pop(root);
ruleAction.destroy();
})
ruleActionPage.onDone.connect(function() {
root.rule.ruleActions.addRuleAction(ruleAction)
ruleActions.addRuleAction(ruleAction)
pageStack.pop(root);
})
}
@ -111,18 +140,19 @@ Page {
}
}
ThinDivider {}
ThinDivider { visible: !root.hasExitActions }
Label {
Layout.fillWidth: true
Layout.margins: app.margins
font.pixelSize: app.mediumFont
text: "Events triggering this rule"
visible: !root.hasExitActions
}
Repeater {
id: eventsRepeater
model: root.rule.eventDescriptors
model: root.hasExitActions ? null : root.rule.eventDescriptors
delegate: SwipeDelegate {
id: eventDelegate
Layout.fillWidth: true
@ -174,9 +204,7 @@ Page {
}
}
}
}
}
swipe.right: MouseArea {
height: eventDelegate.height
@ -198,24 +226,52 @@ Page {
Layout.margins: app.margins
text: eventsRepeater.count == 0 ? "Add an event..." : "Add another event..."
onClicked: root.addEventDescriptor();
visible: !root.hasExitActions
}
ThinDivider {}
Label {
text: "Actions to execute"
text: "Conditions to be met"
font.pixelSize: app.mediumFont
Layout.fillWidth: true
Layout.margins: app.margins
}
StateEvaluatorDelegate {
Layout.fillWidth: true
stateEvaluator: root.rule.stateEvaluator
visible: root.rule.stateEvaluator !== null
}
Button {
Layout.fillWidth: true
Layout.margins: app.margins
text: "Add a condition"
visible: root.rule.stateEvaluator === null
onClicked: {
root.rule.createStateEvaluator();
// root.editStateEvaluator()
}
}
ThinDivider { visible: root.actionsVisible }
Label {
text: root.isStateBased ? "Active state enter actions" : "Actions to execute"
font.pixelSize: app.mediumFont
Layout.fillWidth: true
Layout.margins: app.margins
visible: root.actionsVisible
}
Repeater {
id: actionsRepeater
model: root.rule.ruleActions
model: root.actionsVisible ? root.rule.actions : null
delegate: SwipeDelegate {
id: actionDelegate
Layout.fillWidth: true
property var ruleAction: root.rule.ruleActions.get(index)
property var ruleAction: root.rule.actions.get(index)
property var device: ruleAction.deviceId ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null
property var iface: ruleAction.interfaceName ? Interfaces.findByName(ruleAction.interfaceName) : null
property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
@ -249,7 +305,7 @@ Page {
name: "../images/delete.svg"
color: "red"
}
onClicked: root.rule.ruleActions.removeRuleAction(index)
onClicked: root.rule.actions.removeRuleAction(index)
}
}
}
@ -258,7 +314,72 @@ Page {
Layout.fillWidth: true
Layout.margins: app.margins
text: actionsRepeater.count == 0 ? "Add an action..." : "Add another action..."
onClicked: root.addRuleAction();
onClicked: root.addAction();
visible: root.actionsVisible
}
ThinDivider { visible: root.exitActionsVisible }
Label {
text: "Active state exit actions"
font.pixelSize: app.mediumFont
Layout.fillWidth: true
Layout.margins: app.margins
visible: root.exitActionsVisible
}
Repeater {
id: exitActionsRepeater
model: root.exitActionsVisible ? root.rule.exitActions : null
delegate: SwipeDelegate {
id: exitActionDelegate
Layout.fillWidth: true
property var ruleAction: root.rule.exitActions.get(index)
property var device: ruleAction.deviceId ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null
property var iface: ruleAction.interfaceName ? Interfaces.findByName(ruleAction.interfaceName) : null
property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
property var actionType: deviceClass ? deviceClass.actionTypes.getActionType(ruleAction.actionTypeId)
: iface ? iface.actionTypes.findByName(ruleAction.interfaceAction) : null
contentItem: ColumnLayout {
Label {
Layout.fillWidth: true
text: qsTr("%1 - %2").arg(exitActionDelegate.device ? exitActionDelegate.device.name : exitActionDelegate.iface.displayName).arg(exitActionDelegate.actionType.displayName)
}
RowLayout {
Layout.fillWidth: true
spacing: app.margins
Repeater {
model: exitActionDelegate.ruleAction.ruleActionParams
Label {
text: exitActionDelegate.actionType.paramTypes.getParamType(model.paramTypeId).displayName + " -> " + model.value
font.pixelSize: app.smallFont
}
}
}
}
swipe.right: MouseArea {
height: exitActionDelegate.height
width: height
anchors.right: parent.right
ColorIcon {
anchors.fill: parent
anchors.margins: app.margins
name: "../images/delete.svg"
color: "red"
}
onClicked: root.rule.exitActions.removeRuleAction(index)
}
}
}
Button {
Layout.fillWidth: true
Layout.margins: app.margins
text: actionsRepeater.count == 0 ? "Add an action..." : "Add another action..."
onClicked: root.addExitAction();
visible: root.exitActionsVisible
}
}
}

View File

@ -0,0 +1,20 @@
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import Guh 1.0
import "../components"
Page {
id: root
header: GuhHeader {
text: "Conditions"
onBackPressed: pageStack.pop()
}
property var stateEvaluator: null
StateEvaluatorDelegate {
width: parent.width
stateEvaluator: root.stateEvaluator
}
}

View File

@ -3,7 +3,6 @@ import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Guh 1.0
import "../components"
import "../actiondelegates"
import "../paramdelegates"
Page {

View File

@ -28,7 +28,7 @@ Page {
HeaderButton {
imageSource: header.interfacesMode ? "../images/view-expand.svg" : "../images/view-collapse.svg"
visible: root.ruleAction.interfaceName === ""
visible: root.ruleAction.deviceId || root.ruleAction.interfaceName === ""
onClicked: header.interfacesMode = !header.interfacesMode
}
}
@ -50,8 +50,8 @@ Page {
if (header.interfacesMode) {
if (root.device) {
for (var i = 0; i < Interfaces.count; i++) {
if (deviceClass.interfaces.indexOf(actionTemplateModel.get(i).interfaceName) >= 0) {
actualModel.append(actionTemplateModel.get(i))
if (deviceClass.interfaces.indexOf(Interfaces.get(i).interfaceName) >= 0) {
actualModel.append(Interfaces.get(i))
}
}
} else if (root.ruleAction.interfaceName !== "") {

View File

@ -7,7 +7,7 @@ import Guh 1.0
Page {
id: root
// Needs to be set and filled in with deviceId and actionTypeId
// Needs to be set and filled in with deviceId and actionTypeId or interfaceName and interfaceAction
property var ruleAction
readonly property var device: ruleAction && ruleAction.deviceId ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null

View File

@ -0,0 +1,45 @@
import QtQuick 2.4
import QtQuick.Controls 2.1
import "../components"
import Guh 1.0
Page {
id: root
property alias text: header.text
// a ruleAction object needs to be set and prefilled with either deviceId or interfaceName
property var stateDescriptor: null
readonly property var device: stateDescriptor && stateDescriptor.deviceId ? Engine.deviceManager.devices.getDevice(stateDescriptor.deviceId) : null
readonly property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
signal backPressed();
signal done();
header: GuhHeader {
id: header
onBackPressed: root.backPressed();
}
ListView {
id: listView
anchors.fill: parent
model: root.deviceClass.stateTypes
delegate: ItemDelegate {
text: model.displayName
width: parent.width
onClicked: {
var stateType = root.deviceClass.stateTypes.getStateType(model.id);
console.log("StateType", stateType.id, "selected.")
root.stateDescriptor.stateTypeId = stateType.id;
var paramsPage = pageStack.push(Qt.resolvedUrl("SelectStateDescriptorParamsPage.qml"), {stateDescriptor: root.stateDescriptor})
paramsPage.onBackPressed.connect(function() { pageStack.pop(); });
paramsPage.onCompleted.connect(function() {
pageStack.pop();
root.done();
})
}
}
}
}

View File

@ -0,0 +1,43 @@
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import "../components"
import "../paramdescriptordelegates"
import Guh 1.0
Page {
id: root
// Needs to be set and filled in with deviceId and eventTypeId
property var stateDescriptor: null
readonly property var device: stateDescriptor && stateDescriptor.deviceId ? Engine.deviceManager.devices.getDevice(stateDescriptor.deviceId) : null
readonly property var stateType: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId).stateTypes.getStateType(stateDescriptor.stateTypeId) : null
signal backPressed();
signal completed();
header: GuhHeader {
text: "params"
onBackPressed: root.backPressed();
}
ColumnLayout {
anchors.fill: parent
ParamDescriptorDelegateBase {
id: paramDelegate
Layout.fillWidth: true
paramType: root.stateType
value: paramType.defaultValue
}
Button {
text: "OK"
Layout.fillWidth: true
Layout.margins: app.margins
onClicked: {
root.stateDescriptor.valueOperator = paramDelegate.operatorType
root.stateDescriptor.value = paramDelegate.value
root.completed()
}
}
}
}

View File

@ -0,0 +1,83 @@
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import Guh 1.0
SwipeDelegate {
id: root
Layout.fillWidth: true
property var stateEvaluator: null
property bool showChilds: false
readonly property var device: stateEvaluator ? Engine.deviceManager.devices.getDevice(stateEvaluator.stateDescriptor.deviceId) : null
readonly property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
readonly property var stateType: deviceClass ? deviceClass.stateTypes.getStateType(stateEvaluator.stateDescriptor.stateTypeId) : null
Rectangle {
anchors.fill: parent
border.color: "black"
border.width: 1
color: "transparent"
}
contentItem: ColumnLayout {
Label {
Layout.fillWidth: true
property string operatorString: {
switch (root.stateEvaluator.stateDescriptor.valueOperator) {
case StateDescriptor.ValueOperatorEquals:
return "=";
case StateDescriptor.ValueOperatorNotEquals:
return "!=";
case StateDescriptor.ValueOperatorGreater:
return ">";
case StateDescriptor.ValueOperatorGreaterOrEqual:
return ">=";
case StateDescriptor.ValueOperatorLess:
return "<";
case StateDescriptor.ValueOperatorLessOrEqual:
return "<=";
}
return "FIXME"
}
text: {
if (!root.device) {
return qsTr("Press to edit condition")
}
return qsTr("%1: %2 %3 %4").arg(root.device.name).arg(root.stateType.displayName).arg(operatorString).arg(root.stateEvaluator.stateDescriptor.value)
}
}
Repeater {
model: root.showChilds ? root.stateEvaluator.childEvaluators : null
delegate: Label {
Layout.fillWidth: true
property var stateEvaluator: root.stateEvaluator.childEvaluators.get(index)
property var stateDescriptor: stateEvaluator.stateDescriptor
readonly property var device: Engine.deviceManager.devices.getDevice(stateDescriptor.deviceId)
readonly property var deviceClass: Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId)
readonly property var stateType: deviceClass.stateTypes.getStateType(stateDescriptor.stateTypeId)
property string operatorString: {
switch (stateDescriptor.valueOperator) {
case StateDescriptor.ValueOperatorEquals:
return "=";
case StateDescriptor.ValueOperatorNotEquals:
return "!=";
case StateDescriptor.ValueOperatorGreater:
return ">";
case StateDescriptor.ValueOperatorGreaterOrEqual:
return ">=";
case StateDescriptor.ValueOperatorLess:
return "<";
case StateDescriptor.ValueOperatorLessOrEqual:
return "<=";
}
return "FIXME"
}
text: qsTr("%1 %2: %3 %4 %5%6").arg(root.stateEvaluator.stateOperator === StateEvaluator.StateOperatorAnd ? "and" : "or").arg(device.name).arg(stateType.displayName).arg(operatorString).arg(stateDescriptor.value).arg(stateEvaluator.childEvaluators.count > 0 ? "..." : "")
}
}
}
}

View File

@ -0,0 +1,61 @@
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import Guh 1.0
SwipeDelegate {
id: root
property var stateEvaluator: null
readonly property var device: stateEvaluator ? Engine.deviceManager.devices.getDevice(stateEvaluator.stateDescriptor.deviceId) : null
readonly property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
readonly property var stateType: deviceClass ? deviceClass.stateTypes.getStateType(stateEvaluator.stateDescriptor.stateTypeId) : null
contentItem: ColumnLayout {
SimpleStateEvaluatorDelegate {
Layout.fillWidth: true
stateEvaluator: root.stateEvaluator
onClicked: {
var page = pageStack.push(Qt.resolvedUrl("SelectThingPage.qml"));
page.backPressed.connect(function() {pageStack.pop()})
page.thingSelected.connect(function(device) {
root.stateEvaluator.stateDescriptor.deviceId = device.id
var statePage = pageStack.push(Qt.resolvedUrl("SelectStateDescriptorPage.qml"), {text: "Select state", stateDescriptor: root.stateEvaluator.stateDescriptor})
statePage.backPressed.connect(function() {pageStack.pop()})
statePage.done.connect(function() {pageStack.pop(); pageStack.pop()})
})
}
}
ComboBox {
Layout.fillWidth: true
model: ["and all of those", "or any of those"]
currentIndex: root.stateEvaluator.stateOperator === StateEvaluator.StateOperatorAnd ? 0 : 1
visible: root.stateEvaluator.childEvaluators.count > 0
onActivated: {
root.stateEvaluator.stateOperator = index == 0 ? StateEvaluator.StateOperatorAnd : StateEvaluator.StateOperatorOr
}
}
Repeater {
model: root.stateEvaluator.childEvaluators
delegate: SimpleStateEvaluatorDelegate {
Layout.fillWidth: true
stateEvaluator: root.stateEvaluator.childEvaluators.get(index)
showChilds: true
onClicked: {
pageStack.push(Qt.resolvedUrl("EditStateEvaluatorPage.qml"), {stateEvaluator: stateEvaluator})
}
}
}
Button {
Layout.fillWidth: true
text: "Add a condition"
onClicked: {
root.stateEvaluator.addChildEvaluator()
// root.editStateEvaluator()
}
}
}
}

View File

@ -75,7 +75,7 @@ Page {
Label {
width: listView.column2Width
text: "Device"
text: "Thing"
}
Label {
width: listView.column3Width
@ -134,7 +134,7 @@ Page {
Label {
width: listView.column2Width
text: delegate.device.name
text: model.source === LogEntry.LoggingSourceSystem ? "Nymea Server" : delegate.device.name
elide: Text.ElideRight
}
Label {
@ -144,7 +144,7 @@ Page {
case LogEntry.LoggingSourceStates:
return delegate.deviceClass.stateTypes.getStateType(model.typeId).displayName;
case LogEntry.LoggingSourceSystem:
return "SYS";
return model.loggingEventType === LogEntry.LoggingEventTypeActiveChange ? "Active changed" : "FIXME"
case LogEntry.LoggingSourceActions:
return delegate.deviceClass.actionTypes.getActionType(model.typeId).displayName;
case LogEntry.LoggingSourceEvents:

View File

@ -34,7 +34,10 @@ QList<ParamType *> ParamTypes::paramTypes()
ParamType *ParamTypes::get(int index) const
{
return m_paramTypes.at(index);
if (index >= 0 && index < m_paramTypes.count()) {
return m_paramTypes.at(index);
}
return nullptr;
}
ParamType *ParamTypes::getParamType(const QString &id) const

View File

@ -11,8 +11,9 @@ Rule::Rule(const QUuid &id, QObject *parent) :
QObject(parent),
m_id(id),
m_eventDescriptors(new EventDescriptors(this)),
m_stateEvaluator(new StateEvaluator(this)),
m_ruleActions(new RuleActions(this))
// m_stateEvaluator(new StateEvaluator(this)),
m_actions(new RuleActions(this)),
m_exitActions(new RuleActions(this))
{
}
@ -71,9 +72,29 @@ StateEvaluator *Rule::stateEvaluator() const
return m_stateEvaluator;
}
RuleActions *Rule::ruleActions() const
RuleActions *Rule::actions() const
{
return m_ruleActions;
return m_actions;
}
RuleActions *Rule::exitActions() const
{
return m_exitActions;
}
void Rule::setStateEvaluator(StateEvaluator *stateEvaluator)
{
if (m_stateEvaluator) {
m_stateEvaluator->deleteLater();
}
m_stateEvaluator = stateEvaluator;
m_stateEvaluator->setParent(this);
emit stateEvaluatorChanged();
}
void Rule::createStateEvaluator()
{
setStateEvaluator(new StateEvaluator(this));
}
Rule *Rule::clone() const
@ -89,8 +110,11 @@ Rule *Rule::clone() const
// for (int i = 0; i < this->stateEvaluator()->childEvaluators()->rowCount(); i++) {
// ret->stateEvaluator()->childEvaluators()->
// }
for (int i = 0; i < this->ruleActions()->rowCount(); i++) {
ret->ruleActions()->addRuleAction(this->ruleActions()->get(i)->clone());
for (int i = 0; i < this->actions()->rowCount(); i++) {
ret->actions()->addRuleAction(this->actions()->get(i)->clone());
}
for (int i = 0; i < this->exitActions()->rowCount(); i++) {
ret->exitActions()->addRuleAction(this->exitActions()->get(i)->clone());
}
return ret;
}

View File

@ -16,8 +16,9 @@ class Rule : public QObject
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
Q_PROPERTY(EventDescriptors* eventDescriptors READ eventDescriptors CONSTANT)
Q_PROPERTY(StateEvaluator* stateEvaluator READ stateEvaluator CONSTANT)
Q_PROPERTY(RuleActions* ruleActions READ ruleActions CONSTANT)
Q_PROPERTY(StateEvaluator* stateEvaluator READ stateEvaluator NOTIFY stateEvaluatorChanged)
Q_PROPERTY(RuleActions* actions READ actions CONSTANT)
Q_PROPERTY(RuleActions* exitActions READ exitActions CONSTANT)
public:
explicit Rule(const QUuid &id = QUuid(), QObject *parent = nullptr);
@ -34,7 +35,12 @@ public:
EventDescriptors* eventDescriptors() const;
StateEvaluator *stateEvaluator() const;
RuleActions* ruleActions() const;
RuleActions* actions() const;
RuleActions* exitActions() const;
void setStateEvaluator(StateEvaluator* stateEvaluator);
Q_INVOKABLE void createStateEvaluator();
Rule *clone() const;
@ -42,6 +48,7 @@ signals:
void nameChanged();
void enabledChanged();
void activeChanged();
void stateEvaluatorChanged();
private:
QUuid m_id;
@ -50,7 +57,8 @@ private:
bool m_active = false;
EventDescriptors *m_eventDescriptors = nullptr;
StateEvaluator *m_stateEvaluator = nullptr;
RuleActions *m_ruleActions = nullptr;
RuleActions *m_actions = nullptr;
RuleActions *m_exitActions = nullptr;
};
#endif // RULE_H

View File

@ -10,26 +10,63 @@ StateDescriptor::StateDescriptor(const QUuid &deviceId, StateDescriptor::ValueOp
}
StateDescriptor::StateDescriptor(QObject *parent) : QObject(parent)
{
}
QUuid StateDescriptor::deviceId() const
{
return m_deviceId;
}
void StateDescriptor::setDeviceId(const QUuid &deviceId)
{
if (m_deviceId != deviceId) {
m_deviceId = deviceId;
emit deviceIdChanged();
}
}
StateDescriptor::ValueOperator StateDescriptor::valueOperator() const
{
return m_operator;
}
void StateDescriptor::setValueOperator(StateDescriptor::ValueOperator valueOperator)
{
if (m_operator != valueOperator) {
m_operator = valueOperator;
emit valueOperatorChanged();
}
}
QUuid StateDescriptor::stateTypeId() const
{
return m_stateTypeId;
}
void StateDescriptor::setStateTypeId(const QUuid &stateTypeId)
{
if (m_stateTypeId != stateTypeId) {
m_stateTypeId = stateTypeId;
emit stateTypeIdChanged();
}
}
QVariant StateDescriptor::value() const
{
return m_value;
}
void StateDescriptor::setValue(const QVariant &value)
{
if (m_value != value) {
m_value = value;
emit valueChanged();
}
}
StateDescriptor *StateDescriptor::clone() const
{
StateDescriptor *ret = new StateDescriptor(deviceId(), valueOperator(), stateTypeId(), value());

View File

@ -8,10 +8,10 @@
class StateDescriptor : public QObject
{
Q_OBJECT
Q_PROPERTY(QUuid deviceId READ deviceId CONSTANT)
Q_PROPERTY(ValueOperator valueOperator READ valueOperator CONSTANT)
Q_PROPERTY(QUuid stateTypeId READ stateTypeId CONSTANT)
Q_PROPERTY(QVariant value READ value CONSTANT)
Q_PROPERTY(QUuid deviceId READ deviceId WRITE setDeviceId NOTIFY deviceIdChanged)
Q_PROPERTY(ValueOperator valueOperator READ valueOperator WRITE setValueOperator NOTIFY valueOperatorChanged)
Q_PROPERTY(QUuid stateTypeId READ stateTypeId WRITE setStateTypeId NOTIFY stateTypeIdChanged)
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
public:
enum ValueOperator {
@ -25,13 +25,28 @@ public:
Q_ENUM(ValueOperator)
explicit StateDescriptor(const QUuid &deviceId, ValueOperator valueOperator, const QUuid &stateTypeId, const QVariant &value, QObject *parent = nullptr);
StateDescriptor(QObject *parent = nullptr);
QUuid deviceId() const;
void setDeviceId(const QUuid &deviceId);
ValueOperator valueOperator() const;
void setValueOperator(ValueOperator valueOperator);
QUuid stateTypeId() const;
void setStateTypeId(const QUuid &stateTypeId);
QVariant value() const;
void setValue(const QVariant &value);
StateDescriptor* clone() const;
signals:
void deviceIdChanged();
void valueOperatorChanged();
void stateTypeIdChanged();
void valueChanged();
private:
QUuid m_deviceId;
ValueOperator m_operator = ValueOperatorEquals;

View File

@ -5,7 +5,7 @@
StateEvaluator::StateEvaluator(QObject *parent) : QObject(parent)
{
m_childEvaluators = new StateEvaluators(this);
// m_stateDescriptor = new StateDescriptor(this);
m_stateDescriptor = new StateDescriptor(this);
}
StateEvaluator::StateOperator StateEvaluator::stateOperator() const
@ -15,7 +15,10 @@ StateEvaluator::StateOperator StateEvaluator::stateOperator() const
void StateEvaluator::setStateOperator(StateEvaluator::StateOperator stateOperator)
{
m_operator = stateOperator;
if (m_operator != stateOperator) {
m_operator = stateOperator;
emit stateOperatorChanged();
}
}
StateEvaluators *StateEvaluator::childEvaluators() const
@ -49,3 +52,10 @@ bool StateEvaluator::containsDevice(const QUuid &deviceId) const
}
return false;
}
StateEvaluator* StateEvaluator::addChildEvaluator()
{
StateEvaluator* stateEvaluator = new StateEvaluator(m_childEvaluators);
m_childEvaluators->addStateEvaluator(stateEvaluator);
return stateEvaluator;
}

View File

@ -9,7 +9,7 @@ class StateDescriptor;
class StateEvaluator : public QObject
{
Q_OBJECT
Q_PROPERTY(StateOperator stateOperator READ stateOperator CONSTANT)
Q_PROPERTY(StateOperator stateOperator READ stateOperator WRITE setStateOperator NOTIFY stateOperatorChanged)
Q_PROPERTY(StateEvaluators* childEvaluators READ childEvaluators CONSTANT)
Q_PROPERTY(StateDescriptor* stateDescriptor READ stateDescriptor CONSTANT)
@ -31,6 +31,11 @@ public:
bool containsDevice(const QUuid &deviceId) const;
Q_INVOKABLE StateEvaluator* addChildEvaluator();
signals:
void stateOperatorChanged();
private:
StateOperator m_operator = StateOperatorAnd;
StateEvaluators *m_childEvaluators = nullptr;

View File

@ -22,7 +22,23 @@ QHash<int, QByteArray> StateEvaluators::roleNames() const
return roles;
}
void StateEvaluators::addStateEvaluator(StateEvaluator *stateEvaluator)
{
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
m_list.append(stateEvaluator);
endInsertRows();
emit countChanged();
}
StateEvaluator *StateEvaluators::get(int index) const
{
return m_list.at(index);
}
StateEvaluator *StateEvaluators::take(int index)
{
beginRemoveRows(QModelIndex(), index, index);
return m_list.takeAt(index);
endInsertRows();
emit countChanged();
}

View File

@ -8,6 +8,8 @@ class StateEvaluator;
class StateEvaluators : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
public:
explicit StateEvaluators(QObject *parent = nullptr);
@ -15,7 +17,13 @@ public:
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
StateEvaluator* get(int index) const;
void addStateEvaluator(StateEvaluator* stateEvaluator);
Q_INVOKABLE StateEvaluator* get(int index) const;
StateEvaluator* take(int index);
signals:
void countChanged();
private:
QList<StateEvaluator*> m_list;
};