Merge PR #148: Add support for state based rule action parameters
This commit is contained in:
commit
d510aa13bb
@ -184,6 +184,8 @@ void JsonTypes::init()
|
||||
s_ruleActionParam.insert("o:value", basicTypeRef());
|
||||
s_ruleActionParam.insert("o:eventTypeId", basicTypeToString(Uuid));
|
||||
s_ruleActionParam.insert("o:eventParamTypeId", basicTypeToString(Uuid));
|
||||
s_ruleActionParam.insert("o:stateDeviceId", basicTypeToString(Uuid));
|
||||
s_ruleActionParam.insert("o:stateTypeId", basicTypeToString(Uuid));
|
||||
|
||||
// ParamDescriptor
|
||||
s_paramDescriptor.insert("o:paramTypeId", basicTypeToString(Uuid));
|
||||
@ -592,10 +594,13 @@ QVariantMap JsonTypes::packRuleActionParam(const RuleActionParam &ruleActionPara
|
||||
} else {
|
||||
variantMap.insert("paramName", ruleActionParam.paramName());
|
||||
}
|
||||
// if this ruleaction param has a valid EventTypeId, there is no value
|
||||
if (ruleActionParam.eventTypeId() != EventTypeId()) {
|
||||
|
||||
if (ruleActionParam.isEventBased()) {
|
||||
variantMap.insert("eventTypeId", ruleActionParam.eventTypeId().toString());
|
||||
variantMap.insert("eventParamTypeId", ruleActionParam.eventParamTypeId().toString());
|
||||
} else if (ruleActionParam.isStateBased()) {
|
||||
variantMap.insert("stateDeviceId", ruleActionParam.stateDeviceId().toString());
|
||||
variantMap.insert("stateTypeId", ruleActionParam.stateTypeId().toString());
|
||||
} else {
|
||||
variantMap.insert("value", ruleActionParam.value());
|
||||
}
|
||||
@ -1388,13 +1393,19 @@ RuleActionParam JsonTypes::unpackRuleActionParam(const QVariantMap &ruleActionPa
|
||||
|
||||
ParamTypeId paramTypeId = ParamTypeId(ruleActionParamMap.value("paramTypeId").toString());
|
||||
QString paramName = ruleActionParamMap.value("paramName").toString();
|
||||
QVariant value = ruleActionParamMap.value("value");
|
||||
EventTypeId eventTypeId = EventTypeId(ruleActionParamMap.value("eventTypeId").toString());
|
||||
ParamTypeId eventParamTypeId = ParamTypeId(ruleActionParamMap.value("eventParamTypeId").toString());
|
||||
|
||||
RuleActionParam param;
|
||||
if (paramTypeId.isNull()) {
|
||||
return RuleActionParam(paramName, value, eventTypeId, eventParamTypeId);
|
||||
param = RuleActionParam(paramName);
|
||||
} else {
|
||||
param = RuleActionParam(paramTypeId);
|
||||
}
|
||||
return RuleActionParam(paramTypeId, value, eventTypeId, eventParamTypeId);
|
||||
param.setValue(ruleActionParamMap.value("value"));
|
||||
param.setEventTypeId(EventTypeId(ruleActionParamMap.value("eventTypeId").toString()));
|
||||
param.setEventParamTypeId(ParamTypeId(ruleActionParamMap.value("eventParamTypeId").toString()));
|
||||
param.setStateDeviceId(DeviceId(ruleActionParamMap.value("stateDeviceId").toString()));
|
||||
param.setStateTypeId(StateTypeId(ruleActionParamMap.value("stateTypeId").toString()));
|
||||
return param;
|
||||
}
|
||||
|
||||
/*! Returns a \l{RuleActionParamList} created from the given \a ruleActionParamList. */
|
||||
@ -1414,7 +1425,7 @@ ParamDescriptor JsonTypes::unpackParamDescriptor(const QVariantMap ¶mMap)
|
||||
QMetaObject metaObject = Types::staticMetaObject;
|
||||
int enumIndex = metaObject.indexOfEnumerator("ValueOperator");
|
||||
QMetaEnum metaEnum = metaObject.enumerator(enumIndex);
|
||||
Types::ValueOperator valueOperator = (Types::ValueOperator)metaEnum.keyToValue(operatorString.toLatin1().data());
|
||||
Types::ValueOperator valueOperator = static_cast<Types::ValueOperator>(metaEnum.keyToValue(operatorString.toLatin1().data()));
|
||||
|
||||
if (paramMap.contains("paramTypeId")) {
|
||||
ParamDescriptor param = ParamDescriptor(ParamTypeId(paramMap.value("paramTypeId").toString()), paramMap.value("value"));
|
||||
@ -1455,7 +1466,7 @@ StateEvaluator JsonTypes::unpackStateEvaluator(const QVariantMap &stateEvaluator
|
||||
{
|
||||
StateEvaluator ret(unpackStateDescriptor(stateEvaluatorMap.value("stateDescriptor").toMap()));
|
||||
if (stateEvaluatorMap.contains("operator")) {
|
||||
ret.setOperatorType((Types::StateOperator)s_stateOperator.indexOf(stateEvaluatorMap.value("operator").toString()));
|
||||
ret.setOperatorType(static_cast<Types::StateOperator>(s_stateOperator.indexOf(stateEvaluatorMap.value("operator").toString())));
|
||||
} else {
|
||||
ret.setOperatorType(Types::StateOperatorAnd);
|
||||
}
|
||||
@ -1476,7 +1487,7 @@ StateDescriptor JsonTypes::unpackStateDescriptor(const QVariantMap &stateDescrip
|
||||
QString interface(stateDescriptorMap.value("interface").toString());
|
||||
QString interfaceState(stateDescriptorMap.value("interfaceState").toString());
|
||||
QVariant value = stateDescriptorMap.value("value");
|
||||
Types::ValueOperator operatorType = (Types::ValueOperator)s_valueOperator.indexOf(stateDescriptorMap.value("operator").toString());
|
||||
Types::ValueOperator operatorType = static_cast<Types::ValueOperator>(s_valueOperator.indexOf(stateDescriptorMap.value("operator").toString()));
|
||||
if (!deviceId.isNull() && !stateTypeId.isNull()) {
|
||||
StateDescriptor stateDescriptor(stateTypeId, deviceId, value, operatorType);
|
||||
return stateDescriptor;
|
||||
@ -1495,10 +1506,10 @@ LogFilter JsonTypes::unpackLogFilter(const QVariantMap &logFilterMap)
|
||||
QVariantMap timeFilterMap = timeFilter.toMap();
|
||||
QDateTime startDate; QDateTime endDate;
|
||||
if (timeFilterMap.contains("startDate"))
|
||||
startDate = QDateTime::fromTime_t(timeFilterMap.value("startDate").toInt());
|
||||
startDate = QDateTime::fromTime_t(timeFilterMap.value("startDate").toUInt());
|
||||
|
||||
if (timeFilterMap.contains("endDate"))
|
||||
endDate = QDateTime::fromTime_t(timeFilterMap.value("endDate").toInt());
|
||||
endDate = QDateTime::fromTime_t(timeFilterMap.value("endDate").toUInt());
|
||||
|
||||
filter.addTimeFilter(startDate, endDate);
|
||||
}
|
||||
@ -1507,19 +1518,19 @@ LogFilter JsonTypes::unpackLogFilter(const QVariantMap &logFilterMap)
|
||||
if (logFilterMap.contains("loggingSources")) {
|
||||
QVariantList loggingSources = logFilterMap.value("loggingSources").toList();
|
||||
foreach (const QVariant &source, loggingSources) {
|
||||
filter.addLoggingSource((Logging::LoggingSource)s_loggingSource.indexOf(source.toString()));
|
||||
filter.addLoggingSource(static_cast<Logging::LoggingSource>(s_loggingSource.indexOf(source.toString())));
|
||||
}
|
||||
}
|
||||
if (logFilterMap.contains("loggingLevels")) {
|
||||
QVariantList loggingLevels = logFilterMap.value("loggingLevels").toList();
|
||||
foreach (const QVariant &level, loggingLevels) {
|
||||
filter.addLoggingLevel((Logging::LoggingLevel)s_loggingLevel.indexOf(level.toString()));
|
||||
filter.addLoggingLevel(static_cast<Logging::LoggingLevel>(s_loggingLevel.indexOf(level.toString())));
|
||||
}
|
||||
}
|
||||
if (logFilterMap.contains("eventTypes")) {
|
||||
QVariantList eventTypes = logFilterMap.value("eventTypes").toList();
|
||||
foreach (const QVariant &eventType, eventTypes) {
|
||||
filter.addLoggingEventType((Logging::LoggingEventType)s_loggingEventType.indexOf(eventType.toString()));
|
||||
filter.addLoggingEventType(static_cast<Logging::LoggingEventType>(s_loggingEventType.indexOf(eventType.toString())));
|
||||
}
|
||||
}
|
||||
if (logFilterMap.contains("typeIds")) {
|
||||
@ -1553,7 +1564,7 @@ LogFilter JsonTypes::unpackLogFilter(const QVariantMap &logFilterMap)
|
||||
/*! Returns a \l{RepeatingOption} created from the given \a repeatingOptionMap. */
|
||||
RepeatingOption JsonTypes::unpackRepeatingOption(const QVariantMap &repeatingOptionMap)
|
||||
{
|
||||
RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)s_repeatingMode.indexOf(repeatingOptionMap.value("mode").toString());
|
||||
RepeatingOption::RepeatingMode mode = static_cast<RepeatingOption::RepeatingMode>(s_repeatingMode.indexOf(repeatingOptionMap.value("mode").toString()));
|
||||
|
||||
QList<int> weekDays;
|
||||
if (repeatingOptionMap.contains("weekDays")) {
|
||||
|
||||
@ -440,31 +440,85 @@ void NymeaCore::executeRuleActions(const QList<RuleAction> ruleActions)
|
||||
QList<Action> actions;
|
||||
foreach (const RuleAction &ruleAction, ruleActions) {
|
||||
if (ruleAction.type() == RuleAction::TypeDevice) {
|
||||
actions.append(ruleAction.toAction());
|
||||
Device *device = m_deviceManager->findConfiguredDevice(ruleAction.deviceId());
|
||||
ActionTypeId actionTypeId = ruleAction.actionTypeId();
|
||||
ParamList params;
|
||||
bool ok = true;
|
||||
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
||||
if (ruleActionParam.isValueBased()) {
|
||||
params.append(Param(ruleActionParam.paramTypeId(), ruleActionParam.value()));
|
||||
} else if (ruleActionParam.isStateBased()) {
|
||||
Device *stateDevice = m_deviceManager->findConfiguredDevice(ruleActionParam.stateDeviceId());
|
||||
if (!stateDevice) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.stateDeviceId() << "required by rule action" << ruleAction.id();
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
DeviceClass stateDeviceClass = m_deviceManager->findDeviceClass(stateDevice->deviceClassId());
|
||||
if (!stateDeviceClass.hasStateType(ruleActionParam.stateTypeId())) {
|
||||
qCWarning(dcRuleEngine()) << "Device" << device->name() << device->id() << "does not have a state type" << ruleActionParam.stateTypeId();
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
params.append(Param(ruleActionParam.paramTypeId(), stateDevice->stateValue(ruleActionParam.stateTypeId())));
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
qCWarning(dcRuleEngine()) << "Not executing rule action" << ruleAction.id();
|
||||
continue;
|
||||
}
|
||||
Action action(actionTypeId, device->id());
|
||||
action.setParams(params);
|
||||
actions.append(action);
|
||||
} else {
|
||||
QList<Device*> devices = m_deviceManager->findConfiguredDevices(ruleAction.interface());
|
||||
foreach (Device* device, devices) {
|
||||
DeviceClass dc = m_deviceManager->findDeviceClass(device->deviceClassId());
|
||||
ActionType at = dc.actionTypes().findByName(ruleAction.interfaceAction());
|
||||
if (at.id().isNull()) {
|
||||
DeviceClass deviceClass = m_deviceManager->findDeviceClass(device->deviceClassId());
|
||||
ActionType actionType = deviceClass.actionTypes().findByName(ruleAction.interfaceAction());
|
||||
if (actionType.id().isNull()) {
|
||||
qCWarning(dcRuleEngine()) << "Error creating Action. The given DeviceClass does not implement action:" << ruleAction.interfaceAction();
|
||||
continue;
|
||||
}
|
||||
Action action = Action(at.id(), device->id());
|
||||
|
||||
ParamList params;
|
||||
foreach (const RuleActionParam &rap, ruleAction.ruleActionParams()) {
|
||||
ParamType pt = at.paramTypes().findByName(rap.paramName());
|
||||
if (pt.id().isNull()) {
|
||||
qCWarning(dcRuleEngine()) << "Error creating Action. Failed to match interface param type to DeviceClass paramtype.";
|
||||
bool ok = true;
|
||||
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
||||
ParamType paramType = actionType.paramTypes().findByName(ruleActionParam.paramName());
|
||||
if (paramType.id().isNull()) {
|
||||
qCWarning(dcRuleEngine()) << "Error creating Action. The given ActionType does not have a parameter:" << ruleActionParam.paramName();
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
params.append(Param(pt.id(), rap.value()));
|
||||
if (ruleActionParam.isValueBased()) {
|
||||
params.append(Param(paramType.id(), ruleActionParam.value()));
|
||||
} else if (ruleActionParam.isStateBased()) {
|
||||
Device *stateDevice = m_deviceManager->findConfiguredDevice(ruleActionParam.stateDeviceId());
|
||||
if (!stateDevice) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.stateDeviceId() << "required by rule action" << ruleAction.id();
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
DeviceClass stateDeviceClass = m_deviceManager->findDeviceClass(stateDevice->deviceClassId());
|
||||
if (!stateDeviceClass.hasStateType(ruleActionParam.stateTypeId())) {
|
||||
qCWarning(dcRuleEngine()) << "Device" << device->name() << device->id() << "does not have a state type" << ruleActionParam.stateTypeId();
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
params.append(Param(paramType.id(), stateDevice->stateValue(ruleActionParam.stateTypeId())));
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
qCWarning(dcRuleEngine()) << "Not executing rule action" << ruleAction.id();
|
||||
continue;
|
||||
}
|
||||
|
||||
Action action = Action(actionType.id(), device->id());
|
||||
action.setParams(params);
|
||||
actions.append(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const Action &action, actions) {
|
||||
qCDebug(dcRuleEngine) << "Executing action" << action.actionTypeId() << action.params();
|
||||
DeviceManager::DeviceError status = executeAction(action);
|
||||
@ -654,9 +708,7 @@ void NymeaCore::gotEvent(const Event &event)
|
||||
foreach (RuleActionParam ruleActionParam, ruleAction.ruleActionParams()) {
|
||||
// if this event param should be taken over in this action
|
||||
if (event.eventTypeId() == ruleActionParam.eventTypeId()) {
|
||||
QVariant eventValue = event.params().first().value();
|
||||
|
||||
// TODO: get param names...when an event has more than one parameter
|
||||
QVariant eventValue = event.params().paramValue(ruleActionParam.eventParamTypeId());
|
||||
|
||||
// TODO: limits / scale calculation -> actionValue = eventValue * x
|
||||
// something like a EventParamDescriptor
|
||||
|
||||
@ -383,165 +383,18 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
||||
|
||||
|
||||
// Check actions
|
||||
foreach (const RuleAction &action, rule.actions()) {
|
||||
if (!action.isValid()) {
|
||||
qWarning(dcRuleEngine()) << "Action is incomplete. It must have either actionTypeId and deviceId, or interface and interfaceAction";
|
||||
return RuleErrorActionTypeNotFound;
|
||||
}
|
||||
if (action.type() == RuleAction::TypeDevice) {
|
||||
Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(action.deviceId());
|
||||
if (!device) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for action with actionTypeId" << action.actionTypeId();
|
||||
return RuleErrorDeviceNotFound;
|
||||
}
|
||||
|
||||
DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
||||
if (!deviceClass.hasActionType(action.actionTypeId())) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << action.actionTypeId();
|
||||
return RuleErrorActionTypeNotFound;
|
||||
}
|
||||
|
||||
// check possible eventTypeIds in params
|
||||
if (action.isEventBased()) {
|
||||
foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) {
|
||||
if (ruleActionParam.eventTypeId() != EventTypeId()) {
|
||||
// We have an eventTypeId
|
||||
if (rule.eventDescriptors().isEmpty()) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. RuleAction" << action.actionTypeId() << "contains an eventTypeId, but there are no eventDescriptors.";
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
|
||||
// now check if this eventType is in the eventDescriptorList of this rule
|
||||
if (!checkEventDescriptors(rule.eventDescriptors(), ruleActionParam.eventTypeId())) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. EventTypeId from RuleAction" << action.actionTypeId() << "not in eventDescriptors.";
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
|
||||
// check if the param type of the event and the action match
|
||||
QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId());
|
||||
QVariant v(eventParamType);
|
||||
QVariant::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId());
|
||||
if (eventParamType != actionParamType && !v.canConvert(actionParamType)) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given event param " << ruleActionParam.eventParamTypeId().toString() << "have not the same type:";
|
||||
qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType;
|
||||
qCWarning(dcRuleEngine) << " -> eventParamType:" << eventParamType;
|
||||
return RuleErrorTypesNotMatching;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// verify action params
|
||||
foreach (const ActionType &actionType, deviceClass.actionTypes()) {
|
||||
if (actionType.id() == action.actionTypeId()) {
|
||||
ParamList finalParams = action.toAction().params();
|
||||
DeviceManager::DeviceError paramCheck = NymeaCore::instance()->deviceManager()->verifyParams(actionType.paramTypes(), finalParams);
|
||||
if (paramCheck != DeviceManager::DeviceErrorNoError) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got an invalid actionParam.";
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) {
|
||||
if (!ruleActionParam.isValid()) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got an actionParam with \"value\" AND \"eventTypeId\".";
|
||||
return RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
}
|
||||
|
||||
} else { // Is TypeInterface
|
||||
Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(action.interface());
|
||||
if (!iface.isValid()) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << action.interface();
|
||||
return RuleError::RuleErrorInterfaceNotFound;
|
||||
}
|
||||
ActionType ifaceActionType = iface.actionTypes().findByName(action.interfaceAction());
|
||||
if (ifaceActionType.name().isEmpty()) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << action.interfaceAction();
|
||||
return RuleError::RuleErrorActionTypeNotFound;
|
||||
}
|
||||
foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) {
|
||||
if (!action.ruleActionParams().hasParam(ifaceActionParamType.name())) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << action.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(ifaceActionParamType.type());
|
||||
return RuleError::RuleErrorMissingParameter;
|
||||
}
|
||||
if (!action.ruleActionParam(ifaceActionParamType.name()).value().canConvert(ifaceActionParamType.type())) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << action.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(ifaceActionParamType.type());
|
||||
return RuleError::RuleErrorInvalidParameter;
|
||||
}
|
||||
}
|
||||
// TODO: Check params
|
||||
foreach (const RuleAction &ruleAction, rule.actions()) {
|
||||
RuleError ruleActionError = checkRuleAction(ruleAction, rule);
|
||||
if (ruleActionError != RuleErrorNoError) {
|
||||
return ruleActionError;
|
||||
}
|
||||
}
|
||||
|
||||
// Check exit actions
|
||||
foreach (const RuleAction &ruleAction, rule.exitActions()) {
|
||||
if (!ruleAction.isValid()) {
|
||||
qWarning(dcRuleEngine()) << "Exit Action is incomplete. It must have either actionTypeId and deviceId, or interface and interfaceAction";
|
||||
return RuleErrorActionTypeNotFound;
|
||||
}
|
||||
|
||||
if (ruleAction.type() == RuleAction::TypeDevice) {
|
||||
Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleAction.deviceId());
|
||||
if (!device) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for exit action with actionTypeId" << ruleAction.actionTypeId();
|
||||
return RuleErrorDeviceNotFound;
|
||||
}
|
||||
|
||||
DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
||||
if (!deviceClass.hasActionType(ruleAction.actionTypeId())) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << ruleAction.actionTypeId();
|
||||
return RuleErrorActionTypeNotFound;
|
||||
}
|
||||
|
||||
// verify action params
|
||||
foreach (const ActionType &actionType, deviceClass.actionTypes()) {
|
||||
if (actionType.id() == ruleAction.actionTypeId()) {
|
||||
ParamList finalParams = ruleAction.toAction().params();
|
||||
DeviceManager::DeviceError paramCheck = NymeaCore::instance()->deviceManager()->verifyParams(actionType.paramTypes(), finalParams);
|
||||
if (paramCheck != DeviceManager::DeviceErrorNoError) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got an invalid exit actionParam.";
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exit action can never be event based.
|
||||
if (ruleAction.isEventBased()) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got exitAction with an actionParam containing an eventTypeId. ";
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
|
||||
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
||||
if (!ruleActionParam.isValid()) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got an actionParam with \"value\" AND \"eventTypeId\".";
|
||||
return RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
}
|
||||
|
||||
} else { // Is TypeInterface
|
||||
Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(ruleAction.interface());
|
||||
if (!iface.isValid()) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleAction.interface();
|
||||
return RuleError::RuleErrorInterfaceNotFound;
|
||||
}
|
||||
ActionType ifaceActionType = iface.actionTypes().findByName(ruleAction.interfaceAction());
|
||||
if (ifaceActionType.name().isEmpty()) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << ruleAction.interfaceAction();
|
||||
return RuleError::RuleErrorActionTypeNotFound;
|
||||
}
|
||||
foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) {
|
||||
if (!ruleAction.ruleActionParams().hasParam(ifaceActionParamType.name())) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << ruleAction.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(ifaceActionParamType.type());
|
||||
return RuleError::RuleErrorMissingParameter;
|
||||
}
|
||||
if (!ruleAction.ruleActionParam(ifaceActionParamType.name()).value().canConvert(ifaceActionParamType.type())) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << ruleAction.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(ifaceActionParamType.type());
|
||||
return RuleError::RuleErrorInvalidParameter;
|
||||
}
|
||||
}
|
||||
// TODO: Check params
|
||||
foreach (const RuleAction &ruleExitAction, rule.exitActions()) {
|
||||
RuleError ruleActionError = checkRuleAction(ruleExitAction, rule);
|
||||
if (ruleActionError != RuleErrorNoError) {
|
||||
return ruleActionError;
|
||||
}
|
||||
}
|
||||
|
||||
@ -698,9 +551,9 @@ RuleEngine::RuleError RuleEngine::disableRule(const RuleId &ruleId)
|
||||
*/
|
||||
RuleEngine::RuleError RuleEngine::executeActions(const RuleId &ruleId)
|
||||
{
|
||||
// check if rule exits
|
||||
// check if rule exists
|
||||
if (!m_rules.contains(ruleId)) {
|
||||
qCWarning(dcRuleEngine) << "Not executing rule actions: rule not found.";
|
||||
qCWarning(dcRuleEngine) << "Not executing rule actions: Rule not found.";
|
||||
return RuleErrorRuleNotFound;
|
||||
}
|
||||
|
||||
@ -790,6 +643,15 @@ QList<RuleId> RuleEngine::findRules(const DeviceId &deviceId) const
|
||||
offending = true;
|
||||
break;
|
||||
}
|
||||
foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) {
|
||||
if (ruleActionParam.stateDeviceId() == deviceId) {
|
||||
offending = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (offending) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -799,6 +661,15 @@ QList<RuleId> RuleEngine::findRules(const DeviceId &deviceId) const
|
||||
offending = true;
|
||||
break;
|
||||
}
|
||||
foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) {
|
||||
if (ruleActionParam.stateDeviceId() == deviceId) {
|
||||
offending = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (offending) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -867,6 +738,13 @@ void RuleEngine::removeDeviceFromRule(const RuleId &id, const DeviceId &deviceId
|
||||
for (int i = 0; i < actions.count(); i++) {
|
||||
if (actions.at(i).deviceId() == deviceId) {
|
||||
removeIndexes.append(i);
|
||||
continue;
|
||||
}
|
||||
foreach (const RuleActionParam ¶m, actions.at(i).ruleActionParams()) {
|
||||
if (param.stateDeviceId() == deviceId) {
|
||||
removeIndexes.append(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (removeIndexes.count() > 0) {
|
||||
@ -878,6 +756,13 @@ void RuleEngine::removeDeviceFromRule(const RuleId &id, const DeviceId &deviceId
|
||||
for (int i = 0; i < exitActions.count(); i++) {
|
||||
if (exitActions.at(i).deviceId() == deviceId) {
|
||||
removeIndexes.append(i);
|
||||
continue;
|
||||
}
|
||||
foreach (const RuleActionParam ¶m, exitActions.at(i).ruleActionParams()) {
|
||||
if (param.stateDeviceId() == deviceId) {
|
||||
removeIndexes.append(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (removeIndexes.count() > 0) {
|
||||
@ -1024,15 +909,133 @@ bool RuleEngine::containsState(const StateEvaluator &stateEvaluator, const Event
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RuleEngine::checkEventDescriptors(const QList<EventDescriptor> eventDescriptors, const EventTypeId &eventTypeId)
|
||||
RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction, const Rule &rule)
|
||||
{
|
||||
foreach (const EventDescriptor eventDescriptor, eventDescriptors) {
|
||||
if (eventDescriptor.eventTypeId() == eventTypeId) {
|
||||
return true;
|
||||
if (!ruleAction.isValid()) {
|
||||
qWarning(dcRuleEngine()) << "Action is incomplete. It must have either actionTypeId and deviceId, or interface and interfaceAction";
|
||||
return RuleErrorActionTypeNotFound;
|
||||
}
|
||||
|
||||
ActionType actionType;
|
||||
if (ruleAction.type() == RuleAction::TypeDevice) {
|
||||
Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleAction.deviceId());
|
||||
if (!device) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for action with actionTypeId" << ruleAction.actionTypeId();
|
||||
return RuleErrorDeviceNotFound;
|
||||
}
|
||||
|
||||
DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
||||
if (!deviceClass.hasActionType(ruleAction.actionTypeId())) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << ruleAction.actionTypeId();
|
||||
return RuleErrorActionTypeNotFound;
|
||||
}
|
||||
|
||||
actionType = deviceClass.actionTypes().findById(ruleAction.actionTypeId());
|
||||
} else if (ruleAction.type() == RuleAction::TypeInterface) {
|
||||
Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(ruleAction.interface());
|
||||
if (!iface.isValid()) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleAction.interface();
|
||||
return RuleError::RuleErrorInterfaceNotFound;
|
||||
}
|
||||
actionType = iface.actionTypes().findByName(ruleAction.interfaceAction());
|
||||
if (actionType.name().isEmpty()) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << ruleAction.interfaceAction();
|
||||
return RuleError::RuleErrorActionTypeNotFound;
|
||||
}
|
||||
} else {
|
||||
return RuleErrorActionTypeNotFound;
|
||||
}
|
||||
|
||||
// Verify given params
|
||||
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
||||
RuleError ruleActionParamError = checkRuleActionParam(ruleActionParam, actionType, rule);
|
||||
if (ruleActionParamError != RuleErrorNoError) {
|
||||
return ruleActionParamError;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// Verify all required params are given
|
||||
foreach (const ParamType ¶mType, actionType.paramTypes()) {
|
||||
bool found = false;
|
||||
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
||||
if (ruleActionParam.paramTypeId() == paramType.id()
|
||||
|| ruleActionParam.paramName() == paramType.name()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return RuleErrorMissingParameter;
|
||||
}
|
||||
}
|
||||
|
||||
return RuleErrorNoError;
|
||||
}
|
||||
|
||||
RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ruleActionParam, const ActionType &actionType, const Rule &rule)
|
||||
{
|
||||
// Check param identifier (either paramTypeId or paramName)
|
||||
ParamType paramType;
|
||||
if (!ruleActionParam.paramTypeId().isNull()) {
|
||||
paramType = actionType.paramTypes().findById(ruleActionParam.paramTypeId());
|
||||
} else if (!ruleActionParam.paramName().isEmpty()) {
|
||||
paramType = actionType.paramTypes().findByName(ruleActionParam.paramName());
|
||||
} else {
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
|
||||
if (ruleActionParam.isEventBased()) {
|
||||
// We have an eventTypeId, see if the rule actually has such a event
|
||||
bool found = false;
|
||||
foreach (const EventDescriptor &ed, rule.eventDescriptors()) {
|
||||
if (ed.eventTypeId() == ruleActionParam.eventTypeId()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. EventTypeId" << ruleActionParam.eventTypeId() << "not found in rule's eventDescriptors.";
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
|
||||
// check if the param type of the event and the action match
|
||||
QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId());
|
||||
QVariant v(eventParamType);
|
||||
if (eventParamType != paramType.type() && !v.canConvert(static_cast<int>(paramType.type()))) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given event param " << ruleActionParam.eventParamTypeId().toString() << "have not the same type:";
|
||||
qCWarning(dcRuleEngine) << " -> actionParamType:" << paramType.type();
|
||||
qCWarning(dcRuleEngine) << " -> eventParamType:" << eventParamType;
|
||||
return RuleErrorTypesNotMatching;
|
||||
}
|
||||
} else if (ruleActionParam.isStateBased()) {
|
||||
Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.stateDeviceId());
|
||||
if (!d) {
|
||||
qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleActionParam" << ruleActionParam.paramTypeId() << "not found in system.";
|
||||
return RuleErrorDeviceNotFound;
|
||||
}
|
||||
DeviceClass stateDeviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(d->deviceClassId());
|
||||
StateType stateType = stateDeviceClass.stateTypes().findById(ruleActionParam.stateTypeId());
|
||||
QVariant::Type actionParamType = getActionParamType(actionType.id(), ruleActionParam.paramTypeId());
|
||||
QVariant v(stateType.type());
|
||||
if (actionParamType != stateType.type() && !v.canConvert(static_cast<int>(actionParamType))) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:";
|
||||
qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType;
|
||||
qCWarning(dcRuleEngine) << " -> stateType:" << stateType.type();
|
||||
return RuleErrorTypesNotMatching;
|
||||
}
|
||||
} else { // Is value based
|
||||
if (ruleActionParam.value().isNull()) {
|
||||
qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString();
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
if (paramType.type() != ruleActionParam.value().type() && !ruleActionParam.value().canConvert(static_cast<int>(paramType.type()))) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:";
|
||||
qCWarning(dcRuleEngine) << " -> actionParamType:" << paramType.type();
|
||||
qCWarning(dcRuleEngine) << " -> stateType:" << ruleActionParam.value().type();
|
||||
return RuleErrorTypesNotMatching;
|
||||
}
|
||||
}
|
||||
|
||||
return RuleErrorNoError;
|
||||
}
|
||||
|
||||
QVariant::Type RuleEngine::getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId)
|
||||
@ -1174,7 +1177,7 @@ void RuleEngine::saveRule(const Rule &rule)
|
||||
} else {
|
||||
settings.beginGroup("ParamDescriptor-" + paramDescriptor.paramName());
|
||||
}
|
||||
settings.setValue("valueType", (int)paramDescriptor.value().type());
|
||||
settings.setValue("valueType", static_cast<int>(paramDescriptor.value().type()));
|
||||
settings.setValue("value", paramDescriptor.value());
|
||||
settings.setValue("operator", paramDescriptor.operatorType());
|
||||
settings.endGroup();
|
||||
@ -1204,11 +1207,14 @@ void RuleEngine::saveRule(const Rule &rule)
|
||||
} else {
|
||||
settings.beginGroup("RuleActionParam-" + param.paramName());
|
||||
}
|
||||
settings.setValue("valueType", (int)param.value().type());
|
||||
settings.setValue("valueType", static_cast<int>(param.value().type()));
|
||||
settings.setValue("value", param.value());
|
||||
if (param.eventTypeId() != EventTypeId()) {
|
||||
if (param.isEventBased()) {
|
||||
settings.setValue("eventTypeId", param.eventTypeId().toString());
|
||||
settings.setValue("eventParamTypeId", param.eventParamTypeId());
|
||||
} else if (param.isStateBased()) {
|
||||
settings.setValue("stateDeviceId", param.stateDeviceId().toString());
|
||||
settings.setValue("stateTypeId", param.stateTypeId());
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
@ -1235,7 +1241,7 @@ void RuleEngine::saveRule(const Rule &rule)
|
||||
} else {
|
||||
settings.beginGroup("RuleActionParam-" + param.paramName());
|
||||
}
|
||||
settings.setValue("valueType", (int)param.value().type());
|
||||
settings.setValue("valueType", static_cast<int>(param.value().type()));
|
||||
settings.setValue("value", param.value());
|
||||
settings.endGroup();
|
||||
}
|
||||
@ -1277,7 +1283,7 @@ void RuleEngine::init()
|
||||
|
||||
QList<int> weekDays;
|
||||
QList<int> monthDays;
|
||||
RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt();
|
||||
RepeatingOption::RepeatingMode mode = static_cast<RepeatingOption::RepeatingMode>(settings.value("mode", 0).toInt());
|
||||
|
||||
// Load weekDays
|
||||
int weekDaysCount = settings.beginReadArray("weekDays");
|
||||
@ -1314,7 +1320,7 @@ void RuleEngine::init()
|
||||
|
||||
QList<int> weekDays;
|
||||
QList<int> monthDays;
|
||||
RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt();
|
||||
RepeatingOption::RepeatingMode mode = static_cast<RepeatingOption::RepeatingMode>(settings.value("mode", 0).toInt());
|
||||
|
||||
// Load weekDays
|
||||
int weekDaysCount = settings.beginReadArray("weekDays");
|
||||
@ -1362,24 +1368,24 @@ void RuleEngine::init()
|
||||
|
||||
QVariant value = settings.value("value");
|
||||
if (settings.contains("valueType")) {
|
||||
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
|
||||
QVariant::Type valueType = static_cast<QVariant::Type>(settings.value("valueType").toInt());
|
||||
// Note: only warn, and continue with the QVariant guessed type
|
||||
if (valueType == QVariant::Invalid) {
|
||||
qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the param descriptor" << strippedGroupName << ". The value type will be guessed by QVariant.";
|
||||
} else if (!value.canConvert(valueType)) {
|
||||
} else if (!value.canConvert(static_cast<int>(valueType))) {
|
||||
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the param descriptor value" << value << "to the stored type" << valueType;
|
||||
} else {
|
||||
value.convert(valueType);
|
||||
value.convert(static_cast<int>(valueType));
|
||||
}
|
||||
}
|
||||
|
||||
if (!ParamTypeId(strippedGroupName).isNull()) {
|
||||
ParamDescriptor paramDescriptor(ParamTypeId(strippedGroupName), value);
|
||||
paramDescriptor.setOperatorType((Types::ValueOperator)settings.value("operator").toInt());
|
||||
paramDescriptor.setOperatorType(static_cast<Types::ValueOperator>(settings.value("operator").toInt()));
|
||||
params.append(paramDescriptor);
|
||||
} else {
|
||||
ParamDescriptor paramDescriptor(strippedGroupName, value);
|
||||
paramDescriptor.setOperatorType((Types::ValueOperator)settings.value("operator").toInt());
|
||||
paramDescriptor.setOperatorType(static_cast<Types::ValueOperator>(settings.value("operator").toInt()));
|
||||
params.append(paramDescriptor);
|
||||
}
|
||||
settings.endGroup();
|
||||
@ -1415,32 +1421,34 @@ void RuleEngine::init()
|
||||
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-"));
|
||||
EventTypeId eventTypeId = EventTypeId(settings.value("eventTypeId", EventTypeId()).toString());
|
||||
ParamTypeId eventParamTypeId = ParamTypeId(settings.value("eventParamTypeId", ParamTypeId()).toString());
|
||||
DeviceId stateDeviceId = DeviceId(settings.value("stateDeviceId", DeviceId()).toString());
|
||||
StateTypeId stateTypeId = StateTypeId(settings.value("stateTypeId", StateTypeId()).toString());
|
||||
QVariant value = settings.value("value");
|
||||
if (settings.contains("valueType")) {
|
||||
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
|
||||
QVariant::Type valueType = static_cast<QVariant::Type>(settings.value("valueType").toInt());
|
||||
// Note: only warn, and continue with the QVariant guessed type
|
||||
if (valueType == QVariant::Invalid) {
|
||||
qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the rule action param " << strippedParamTypeIdString << ". The value type will be guessed by QVariant.";
|
||||
} else if (!value.canConvert(valueType)) {
|
||||
} else if (!value.canConvert(static_cast<int>(valueType))) {
|
||||
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the rule action param value" << value << "to the stored type" << valueType;
|
||||
} else {
|
||||
value.convert(valueType);
|
||||
value.convert(static_cast<int>(valueType));
|
||||
}
|
||||
}
|
||||
|
||||
RuleActionParam param;
|
||||
if (!ParamTypeId(strippedParamTypeIdString).isNull()) {
|
||||
RuleActionParam param(ParamTypeId(strippedParamTypeIdString),
|
||||
value,
|
||||
eventTypeId,
|
||||
eventParamTypeId);
|
||||
params.append(param);
|
||||
// By ParamTypeId
|
||||
param = RuleActionParam(ParamTypeId(strippedParamTypeIdString), value);
|
||||
} else {
|
||||
RuleActionParam param(strippedParamTypeIdString,
|
||||
value,
|
||||
eventTypeId,
|
||||
eventParamTypeId);
|
||||
params.append(param);
|
||||
// By param name
|
||||
param = RuleActionParam(strippedParamTypeIdString, value);
|
||||
}
|
||||
param.setEventTypeId(eventTypeId);
|
||||
param.setEventParamTypeId(eventParamTypeId);
|
||||
param.setStateDeviceId(stateDeviceId);
|
||||
param.setStateTypeId(stateTypeId);
|
||||
params.append(param);
|
||||
settings.endGroup();
|
||||
}
|
||||
}
|
||||
@ -1472,14 +1480,14 @@ void RuleEngine::init()
|
||||
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-"));
|
||||
QVariant value = settings.value("value");
|
||||
if (settings.contains("valueType")) {
|
||||
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
|
||||
QVariant::Type valueType = static_cast<QVariant::Type>(settings.value("valueType").toInt());
|
||||
// Note: only warn, and continue with the QVariant guessed type
|
||||
if (valueType == QVariant::Invalid) {
|
||||
qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the rule action param " << strippedParamTypeIdString << ". The value type will be guessed by QVariant.";
|
||||
} else if (!value.canConvert(valueType)) {
|
||||
} else if (!value.canConvert(static_cast<int>(valueType))) {
|
||||
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the rule action param value" << value << "to the stored type" << valueType;
|
||||
} else {
|
||||
value.convert(valueType);
|
||||
value.convert(static_cast<int>(valueType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -104,7 +104,9 @@ private:
|
||||
bool containsEvent(const Rule &rule, const Event &event, const DeviceClassId &deviceClassId);
|
||||
bool containsState(const StateEvaluator &stateEvaluator, const Event &stateChangeEvent);
|
||||
|
||||
bool checkEventDescriptors(const QList<EventDescriptor> eventDescriptors, const EventTypeId &eventTypeId);
|
||||
RuleError checkRuleAction(const RuleAction &ruleAction, const Rule &rule);
|
||||
RuleError checkRuleActionParam(const RuleActionParam &ruleActionParam, const ActionType &actionType, const Rule &rule);
|
||||
|
||||
QVariant::Type getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId);
|
||||
QVariant::Type getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId);
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ QDateTime TimeEventItem::dateTime() const
|
||||
}
|
||||
|
||||
/*! Sets the dateTime of this \l{TimeEventItem} to the given \a timeStamp. */
|
||||
void TimeEventItem::setDateTime(const int &timeStamp)
|
||||
void TimeEventItem::setDateTime(const uint &timeStamp)
|
||||
{
|
||||
m_dateTime = QDateTime::fromTime_t(timeStamp);
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ public:
|
||||
TimeEventItem();
|
||||
|
||||
QDateTime dateTime() const;
|
||||
void setDateTime(const int &timeStamp);
|
||||
void setDateTime(const uint &timeStamp);
|
||||
|
||||
QTime time() const;
|
||||
void setTime(const QTime &time);
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
class LIBNYMEA_EXPORT ActionType
|
||||
{
|
||||
public:
|
||||
ActionType(const ActionTypeId &id);
|
||||
ActionType(const ActionTypeId &id = ActionTypeId());
|
||||
|
||||
ActionTypeId id() const;
|
||||
|
||||
|
||||
@ -49,6 +49,11 @@
|
||||
|
||||
#include "eventdescriptor.h"
|
||||
|
||||
EventDescriptor::EventDescriptor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Constructs an EventDescriptor describing an \l{Event} with the given \a eventTypeId, \a deviceId and the given \a paramDescriptors. */
|
||||
EventDescriptor::EventDescriptor(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList<ParamDescriptor> ¶mDescriptors):
|
||||
m_eventTypeId(eventTypeId),
|
||||
|
||||
@ -41,6 +41,7 @@ public:
|
||||
TypeInterface
|
||||
};
|
||||
|
||||
EventDescriptor();
|
||||
EventDescriptor(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList<ParamDescriptor> ¶mDescriptors = QList<ParamDescriptor>());
|
||||
EventDescriptor(const QString &interface, const QString &interfaceEvent, const QList<ParamDescriptor> ¶mDescriptors = QList<ParamDescriptor>());
|
||||
|
||||
|
||||
@ -99,7 +99,17 @@ RuleAction::Type RuleAction::type() const
|
||||
bool RuleAction::isEventBased() const
|
||||
{
|
||||
foreach (const RuleActionParam ¶m, m_ruleActionParams) {
|
||||
if (param.eventTypeId() != EventTypeId()) {
|
||||
if (param.isEventBased()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RuleAction::isStateBased() const
|
||||
{
|
||||
foreach (const RuleActionParam ¶m, m_ruleActionParams) {
|
||||
if (param.isStateBased()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -167,7 +177,7 @@ RuleActionParam RuleAction::ruleActionParam(const ParamTypeId &ruleActionParamTy
|
||||
return ruleActionParam;
|
||||
}
|
||||
}
|
||||
return RuleActionParam(QString());
|
||||
return RuleActionParam();
|
||||
}
|
||||
|
||||
/*! Returns the \l{RuleActionParam} of this RuleAction with the given \a ruleActionParamName.
|
||||
@ -180,7 +190,7 @@ RuleActionParam RuleAction::ruleActionParam(const QString &ruleActionParamName)
|
||||
return ruleActionParam;
|
||||
}
|
||||
}
|
||||
return RuleActionParam(QString());
|
||||
return RuleActionParam();
|
||||
}
|
||||
|
||||
/*! Copy the data to a \l{RuleAction} from an \a other rule action. */
|
||||
|
||||
@ -45,6 +45,7 @@ public:
|
||||
Type type() const;
|
||||
|
||||
bool isEventBased() const;
|
||||
bool isStateBased() const;
|
||||
|
||||
Action toAction() const;
|
||||
|
||||
|
||||
@ -32,6 +32,21 @@
|
||||
A RuleActionParam allows rules to take over an \l{Event} parameter into a rule
|
||||
\l{RuleAction}.
|
||||
|
||||
RuleActionParams are identified by either paramTypeId or paramName (for interface based actions).
|
||||
|
||||
The parameter value can either be a static \l{value}, a pair of \l{EventTypeId} and \l{ParamTypeId} or a pair of
|
||||
\l{DeviceId} and \l{StateTypeId}.
|
||||
|
||||
When composing the actual Param for the executeAction() call the value is generated as follows:
|
||||
- Static value params are filled with \l{RuleActionParam::paramTypeId()} and the \l{RuleActionParam::value()}
|
||||
- Event based actions are filled with \l{RuleActionParam::paramTypeId()} and the param value of the event that triggered this rule, identified by \l{RuleActionParam::eventTypeId()} and \l{RuleActionParam::eventParamTypeId()}
|
||||
- State based actions are filled with \l{RuleActionParam::paramTypeId()} and the current value of the state identified by \l{RuleActionParam::deviceId()} and \l{RuleActionParam::stateTypeId()}
|
||||
|
||||
If the param types are not matching, nymea will do a best effort to cast the values. E.g. a RuleActionParam for
|
||||
a param of type "string" and a state of type "int" would cast the integer to a string which would always work.
|
||||
However, the other way round, having a parameter requiring an "int" value, and reading the value from a state of type
|
||||
"string" might work, if the string does only hold numbers but would fail.
|
||||
|
||||
\sa nymeaserver::Rule, RuleAction,
|
||||
*/
|
||||
|
||||
@ -41,33 +56,68 @@
|
||||
* \sa Param, */
|
||||
RuleActionParam::RuleActionParam(const Param ¶m) :
|
||||
m_paramTypeId(param.paramTypeId()),
|
||||
m_value(param.value()),
|
||||
m_eventTypeId(EventTypeId()),
|
||||
m_eventParamTypeId(ParamTypeId())
|
||||
m_value(param.value())
|
||||
{
|
||||
}
|
||||
|
||||
/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId, \a value, \a eventTypeId and \a eventParamTypeId.
|
||||
/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId and \a value.
|
||||
* \sa Param, Event, */
|
||||
RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId) :
|
||||
RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value):
|
||||
m_paramTypeId(paramTypeId),
|
||||
m_value(value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId, \a eventTypeId and \a eventParamTypeId.
|
||||
* \sa Param, Event, */
|
||||
RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId):
|
||||
m_paramTypeId(paramTypeId),
|
||||
m_value(value),
|
||||
m_eventTypeId(eventTypeId),
|
||||
m_eventParamTypeId(eventParamTypeId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a value, \a eventTypeId and \a eventParamTypeId.
|
||||
/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId, \a stateDeviceId and \a stateTypeId.
|
||||
* \sa Param, Event, */
|
||||
RuleActionParam::RuleActionParam(const QString ¶mName, const QVariant &value, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId):
|
||||
RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId):
|
||||
m_paramTypeId(paramTypeId),
|
||||
m_stateDeviceId(stateDeviceId),
|
||||
m_stateTypeId(stateTypeId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Constructs a \l{RuleActionParam} with the given \a paramName and \a value.
|
||||
* \sa Param, Event, */
|
||||
RuleActionParam::RuleActionParam(const QString ¶mName, const QVariant &value):
|
||||
m_paramName(paramName),
|
||||
m_value(value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a eventTypeId and \a eventParamTypeId.
|
||||
* \sa Param, Event, */
|
||||
RuleActionParam::RuleActionParam(const QString ¶mName, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId):
|
||||
m_paramName(paramName),
|
||||
m_value(value),
|
||||
m_eventTypeId(eventTypeId),
|
||||
m_eventParamTypeId(eventParamTypeId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a stateDeviceId and \a stateTypeId.
|
||||
* \sa Param, Event, */
|
||||
RuleActionParam::RuleActionParam(const QString ¶mName, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId):
|
||||
m_paramName(paramName),
|
||||
m_stateDeviceId(stateDeviceId),
|
||||
m_stateTypeId(stateTypeId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Returns the \l ParamTypeId of this \l RuleActionParam. */
|
||||
ParamTypeId RuleActionParam::paramTypeId() const
|
||||
{
|
||||
@ -80,18 +130,6 @@ QString RuleActionParam::paramName() const
|
||||
return m_paramName;
|
||||
}
|
||||
|
||||
/*! Returns the eventParamTypeId of this RuleActionParam. */
|
||||
ParamTypeId RuleActionParam::eventParamTypeId() const
|
||||
{
|
||||
return m_eventParamTypeId;
|
||||
}
|
||||
|
||||
/*! Sets the \a eventParamTypeId of this RuleActionParam. */
|
||||
void RuleActionParam::setEventParamTypeId(const ParamTypeId &eventParamTypeId)
|
||||
{
|
||||
m_eventParamTypeId = eventParamTypeId;
|
||||
}
|
||||
|
||||
/*! Returns the value of this RuleActionParam. */
|
||||
QVariant RuleActionParam::value() const
|
||||
{
|
||||
@ -104,14 +142,6 @@ void RuleActionParam::setValue(const QVariant &value)
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
/*! Returns true if the \tt{(paramTypeId AND value) XOR (paramTypeId AND eventTypeId AND eventParamName)} of this RuleActionParam are set.*/
|
||||
bool RuleActionParam::isValid() const
|
||||
{
|
||||
bool validValue = (!m_paramTypeId.isNull() && m_value.isValid() && m_eventTypeId.isNull() && m_eventParamTypeId.isNull());
|
||||
bool validEvent = (!m_paramTypeId.isNull() && !m_value.isValid() && !m_eventTypeId.isNull() && !m_eventParamTypeId.isNull());
|
||||
return validValue ^ validEvent;
|
||||
}
|
||||
|
||||
/*! Return the EventTypeId of the \l{Event} with the \l{Param} which will be taken over in the \l{RuleAction}. */
|
||||
EventTypeId RuleActionParam::eventTypeId() const
|
||||
{
|
||||
@ -124,6 +154,66 @@ void RuleActionParam::setEventTypeId(const EventTypeId &eventTypeId)
|
||||
m_eventTypeId = eventTypeId;
|
||||
}
|
||||
|
||||
/*! Returns the eventParamTypeId of this RuleActionParam. */
|
||||
ParamTypeId RuleActionParam::eventParamTypeId() const
|
||||
{
|
||||
return m_eventParamTypeId;
|
||||
}
|
||||
|
||||
/*! Sets the \a eventParamTypeId of this RuleActionParam. */
|
||||
void RuleActionParam::setEventParamTypeId(const ParamTypeId &eventParamTypeId)
|
||||
{
|
||||
m_eventParamTypeId = eventParamTypeId;
|
||||
}
|
||||
|
||||
/*! Returns the deviceId identifying the device to use a state value from. */
|
||||
DeviceId RuleActionParam::stateDeviceId() const
|
||||
{
|
||||
return m_stateDeviceId;
|
||||
}
|
||||
|
||||
/*! Sets the deviceId identifying the device to use a state value from. */
|
||||
void RuleActionParam::setStateDeviceId(const DeviceId &stateDeviceId)
|
||||
{
|
||||
m_stateDeviceId = stateDeviceId;
|
||||
}
|
||||
|
||||
/*! Returns the stateTypeId identifying the state to use the value. */
|
||||
StateTypeId RuleActionParam::stateTypeId() const
|
||||
{
|
||||
return m_stateTypeId;
|
||||
}
|
||||
|
||||
/*! Sets the stateTypeId identifying the state to use the value from. */
|
||||
void RuleActionParam::setStateTypeId(const StateTypeId &stateTypeId)
|
||||
{
|
||||
m_stateTypeId = stateTypeId;
|
||||
}
|
||||
|
||||
/*! Returns true if the \tt{(paramTypeId AND value) XOR (paramTypeId AND eventTypeId AND eventParamName)} of this RuleActionParam are set.*/
|
||||
bool RuleActionParam::isValid() const
|
||||
{
|
||||
if (m_paramTypeId.isNull() && m_paramName.isNull()) {
|
||||
return false;
|
||||
}
|
||||
return isValueBased() ^ isEventBased() ^ isStateBased();
|
||||
}
|
||||
|
||||
bool RuleActionParam::isValueBased() const
|
||||
{
|
||||
return !m_value.isNull();
|
||||
}
|
||||
|
||||
bool RuleActionParam::isEventBased() const
|
||||
{
|
||||
return !m_eventTypeId.isNull() && !m_eventParamTypeId.isNull();
|
||||
}
|
||||
|
||||
bool RuleActionParam::isStateBased() const
|
||||
{
|
||||
return !m_stateDeviceId.isNull() && !m_stateTypeId.isNull();
|
||||
}
|
||||
|
||||
/*! Writes the paramTypeId, value, eventId and eventParamTypeId of the given \a ruleActionParam to \a dbg. */
|
||||
QDebug operator<<(QDebug dbg, const RuleActionParam &ruleActionParam)
|
||||
{
|
||||
|
||||
@ -36,29 +36,46 @@ class LIBNYMEA_EXPORT RuleActionParam
|
||||
{
|
||||
public:
|
||||
RuleActionParam(const Param ¶m = Param());
|
||||
RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant(), const EventTypeId &eventTypeId = EventTypeId(), const ParamTypeId &eventParamTypeId = ParamTypeId());
|
||||
RuleActionParam(const QString ¶mName, const QVariant &value = QVariant(), const EventTypeId &eventTypeId = EventTypeId(), const ParamTypeId &eventParamTypeId = ParamTypeId());
|
||||
RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant());
|
||||
RuleActionParam(const ParamTypeId ¶mTypeId, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId);
|
||||
RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId);
|
||||
RuleActionParam(const QString ¶mName, const QVariant &value = QVariant());
|
||||
RuleActionParam(const QString ¶mName, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId);
|
||||
RuleActionParam(const QString ¶mName, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId);
|
||||
|
||||
ParamTypeId paramTypeId() const;
|
||||
QString paramName() const;
|
||||
|
||||
ParamTypeId eventParamTypeId() const;
|
||||
void setEventParamTypeId(const ParamTypeId &eventParamTypeId);
|
||||
bool isValid() const;
|
||||
bool isValueBased() const;
|
||||
bool isEventBased() const;
|
||||
bool isStateBased() const;
|
||||
|
||||
QVariant value() const;
|
||||
void setValue(const QVariant &value);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
EventTypeId eventTypeId() const;
|
||||
void setEventTypeId(const EventTypeId &eventTypeId);
|
||||
|
||||
ParamTypeId eventParamTypeId() const;
|
||||
void setEventParamTypeId(const ParamTypeId &eventParamTypeId);
|
||||
|
||||
DeviceId stateDeviceId() const;
|
||||
void setStateDeviceId(const DeviceId &deviceId);
|
||||
|
||||
StateTypeId stateTypeId() const;
|
||||
void setStateTypeId(const StateTypeId &stateTypeId);
|
||||
|
||||
private:
|
||||
ParamTypeId m_paramTypeId;
|
||||
QString m_paramName;
|
||||
QVariant m_value;
|
||||
|
||||
EventTypeId m_eventTypeId;
|
||||
ParamTypeId m_eventParamTypeId;
|
||||
|
||||
DeviceId m_stateDeviceId;
|
||||
StateTypeId m_stateTypeId;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(RuleActionParam)
|
||||
|
||||
@ -1486,6 +1486,8 @@
|
||||
"o:eventTypeId": "Uuid",
|
||||
"o:paramName": "String",
|
||||
"o:paramTypeId": "Uuid",
|
||||
"o:stateDeviceId": "Uuid",
|
||||
"o:stateTypeId": "Uuid",
|
||||
"o:value": "$ref:BasicType"
|
||||
},
|
||||
"RuleDescription": {
|
||||
|
||||
@ -93,9 +93,10 @@ private slots:
|
||||
void enableDisableRule();
|
||||
|
||||
void testEventBasedAction();
|
||||
|
||||
void testEventBasedRuleWithExitAction();
|
||||
|
||||
void testStateBasedAction();
|
||||
|
||||
void removePolicyUpdate();
|
||||
void removePolicyCascade();
|
||||
void removePolicyUpdateRendersUselessRule();
|
||||
@ -118,7 +119,6 @@ private slots:
|
||||
|
||||
void testHousekeeping_data();
|
||||
void testHousekeeping();
|
||||
|
||||
};
|
||||
|
||||
void TestRules::cleanupMockHistory() {
|
||||
@ -1149,7 +1149,6 @@ void TestRules::loadStoreConfig()
|
||||
|
||||
QVariantMap action2;
|
||||
action2.insert("actionTypeId", mockActionIdWithParams);
|
||||
qDebug() << "got action id" << mockActionIdWithParams;
|
||||
action2.insert("deviceId", m_mockDeviceId);
|
||||
QVariantList action2Params;
|
||||
QVariantMap action2Param1;
|
||||
@ -1221,6 +1220,7 @@ void TestRules::loadStoreConfig()
|
||||
actionsInterfaces.append(actionInterfaces);
|
||||
|
||||
// rule 1
|
||||
qCDebug(dcTests()) << "Adding rule 1";
|
||||
QVariantMap params;
|
||||
QVariantList actions;
|
||||
actions.append(action1);
|
||||
@ -1235,6 +1235,7 @@ void TestRules::loadStoreConfig()
|
||||
verifyRuleError(response);
|
||||
|
||||
// rule 2
|
||||
qCDebug(dcTests()) << "Adding rule 2";
|
||||
QVariantMap params2;
|
||||
QVariantList actions2;
|
||||
actions2.append(action1);
|
||||
@ -1250,6 +1251,7 @@ void TestRules::loadStoreConfig()
|
||||
verifyRuleError(response2);
|
||||
|
||||
// rule 3
|
||||
qCDebug(dcTests()) << "Adding rule 3";
|
||||
QVariantMap params3;
|
||||
QVariantList actions3;
|
||||
actions3.append(validActionEventBased);
|
||||
@ -1262,6 +1264,7 @@ void TestRules::loadStoreConfig()
|
||||
verifyRuleError(response3);
|
||||
|
||||
// rule 4, interface based
|
||||
qCDebug(dcTests()) << "Adding rule 4";
|
||||
QVariantMap params4;
|
||||
params4.insert("name", "TestRule4 - Interface based");
|
||||
params4.insert("eventDescriptors", eventDescriptorsInterfaces);
|
||||
@ -1272,10 +1275,12 @@ void TestRules::loadStoreConfig()
|
||||
RuleId newRuleId4 = RuleId(response4.toMap().value("params").toMap().value("ruleId").toString());
|
||||
verifyRuleError(response4);
|
||||
|
||||
qCDebug(dcTests()) << "Getting rules";
|
||||
response = injectAndWait("Rules.GetRules");
|
||||
QVariantList rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList();
|
||||
qDebug() << "GetRules before server shutdown:" << response;
|
||||
|
||||
qCDebug(dcTests()) << "Restarting server";
|
||||
restartServer();
|
||||
|
||||
response = injectAndWait("Rules.GetRules");
|
||||
@ -2214,6 +2219,98 @@ void TestRules::testEventBasedRuleWithExitAction()
|
||||
|
||||
}
|
||||
|
||||
void TestRules::testStateBasedAction()
|
||||
{
|
||||
QNetworkAccessManager nam;
|
||||
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
|
||||
|
||||
// Init bool state to true
|
||||
spy.clear();
|
||||
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateId.toString()).arg(true)));
|
||||
QNetworkReply *reply = nam.get(request);
|
||||
spy.wait();
|
||||
QCOMPARE(spy.count(), 1);
|
||||
reply->deleteLater();
|
||||
|
||||
// Init int state to 11
|
||||
spy.clear();
|
||||
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateId.toString()).arg(11)));
|
||||
reply = nam.get(request);
|
||||
spy.wait();
|
||||
QCOMPARE(spy.count(), 1);
|
||||
reply->deleteLater();
|
||||
|
||||
// Add a rule
|
||||
QVariantMap addRuleParams;
|
||||
QVariantMap eventDescriptor;
|
||||
eventDescriptor.insert("eventTypeId", mockEvent1Id);
|
||||
eventDescriptor.insert("deviceId", m_mockDeviceId);
|
||||
addRuleParams.insert("eventDescriptors", QVariantList() << eventDescriptor);
|
||||
addRuleParams.insert("name", "TestRule");
|
||||
addRuleParams.insert("enabled", true);
|
||||
|
||||
QVariantList actions;
|
||||
QVariantMap action;
|
||||
QVariantList ruleActionParams;
|
||||
QVariantMap param1;
|
||||
param1.insert("paramTypeId", mockActionParam1ParamTypeId);
|
||||
param1.insert("stateDeviceId", m_mockDeviceId);
|
||||
param1.insert("stateTypeId", mockIntStateId);
|
||||
QVariantMap param2;
|
||||
param2.insert("paramTypeId", mockActionParam2ParamTypeId);
|
||||
param2.insert("stateDeviceId", m_mockDeviceId);
|
||||
param2.insert("stateTypeId", mockBoolStateId);
|
||||
ruleActionParams.append(param1);
|
||||
ruleActionParams.append(param2);
|
||||
|
||||
actions.clear();
|
||||
action.insert("deviceId", m_mockDeviceId);
|
||||
action.insert("actionTypeId", mockActionIdWithParams);
|
||||
action.insert("ruleActionParams", ruleActionParams);
|
||||
actions.append(action);
|
||||
addRuleParams.insert("actions", actions);
|
||||
|
||||
qCDebug(dcTests) << "Adding rule";
|
||||
|
||||
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
|
||||
verifyRuleError(response);
|
||||
|
||||
// trigger event
|
||||
spy.clear();
|
||||
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1Id.toString())));
|
||||
reply = nam.get(request);
|
||||
spy.wait();
|
||||
QCOMPARE(spy.count(), 1);
|
||||
reply->deleteLater();
|
||||
|
||||
LogFilter filter;
|
||||
filter.addDeviceId(m_mockDeviceId);
|
||||
filter.addTypeId(mockActionIdWithParams);
|
||||
QList<LogEntry> entries = NymeaCore::instance()->logEngine()->logEntries(filter);
|
||||
qCDebug(dcTests()) << "Log entries:" << entries;
|
||||
|
||||
// set bool state to false
|
||||
spy.clear();
|
||||
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateId.toString()).arg(false)));
|
||||
reply = nam.get(request);
|
||||
spy.wait();
|
||||
QCOMPARE(spy.count(), 1);
|
||||
reply->deleteLater();
|
||||
|
||||
// trigger event
|
||||
spy.clear();
|
||||
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1Id.toString())));
|
||||
reply = nam.get(request);
|
||||
spy.wait();
|
||||
QCOMPARE(spy.count(), 1);
|
||||
reply->deleteLater();
|
||||
|
||||
entries = NymeaCore::instance()->logEngine()->logEntries(filter);
|
||||
qCDebug(dcTests()) << "Log entries:" << entries;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void TestRules::removePolicyUpdate()
|
||||
{
|
||||
// ADD parent device
|
||||
@ -2377,6 +2474,7 @@ void TestRules::removePolicyUpdateRendersUselessRule()
|
||||
params.insert("deviceClassId", mockParentDeviceClassId);
|
||||
params.insert("name", "Parent device");
|
||||
|
||||
qCDebug(dcTests()) << "Adding device";
|
||||
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
|
||||
verifyDeviceError(response);
|
||||
|
||||
@ -2384,6 +2482,7 @@ void TestRules::removePolicyUpdateRendersUselessRule()
|
||||
QVERIFY(!parentDeviceId.isNull());
|
||||
|
||||
// find child device
|
||||
qCDebug(dcTests()) << "Gettin devices";
|
||||
response = injectAndWait("Devices.GetConfiguredDevices");
|
||||
|
||||
QVariantList devices = response.toMap().value("params").toMap().value("devices").toList();
|
||||
@ -2414,26 +2513,34 @@ void TestRules::removePolicyUpdateRendersUselessRule()
|
||||
QVariantMap action;
|
||||
action.insert("deviceId", childDeviceId);
|
||||
action.insert("actionTypeId", mockParentChildActionId);
|
||||
QVariantMap ruleActionParam;
|
||||
ruleActionParam.insert("paramTypeId", mockParentChildActionId);
|
||||
ruleActionParam.insert("value", true);
|
||||
action.insert("ruleActionParams", QVariantList() << ruleActionParam);
|
||||
params.insert("actions", QVariantList() << action);
|
||||
|
||||
qCDebug(dcTests()) << "Adding Rule";
|
||||
response = injectAndWait("Rules.AddRule", params);
|
||||
verifyRuleError(response);
|
||||
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
|
||||
QVERIFY2(!ruleId.isNull(), "Could not get ruleId");
|
||||
|
||||
// Try to remove child device
|
||||
qCDebug(dcTests()) << "Removing device (expecing failure - device is child)";
|
||||
params.clear(); response.clear();
|
||||
params.insert("deviceId", childDeviceId);
|
||||
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
|
||||
verifyDeviceError(response, DeviceManager::DeviceErrorDeviceIsChild);
|
||||
|
||||
// Try to remove child device
|
||||
qCDebug(dcTests()) << "Removing device (expeciting failure - device in use)";
|
||||
params.clear(); response.clear();
|
||||
params.insert("deviceId", parentDeviceId);
|
||||
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
|
||||
verifyDeviceError(response, DeviceManager::DeviceErrorDeviceInRule);
|
||||
|
||||
// Remove policy
|
||||
qCDebug(dcTests()) << "Removing device with update policy";
|
||||
params.clear(); response.clear();
|
||||
params.insert("deviceId", parentDeviceId);
|
||||
params.insert("removePolicy", "RemovePolicyUpdate");
|
||||
@ -2441,6 +2548,7 @@ void TestRules::removePolicyUpdateRendersUselessRule()
|
||||
verifyDeviceError(response);
|
||||
|
||||
// get updated rule. It should've been deleted given it ended up with no actions
|
||||
qCDebug(dcTests()) << "Getting details";
|
||||
params.clear();
|
||||
params.insert("ruleId", ruleId);
|
||||
response = injectAndWait("Rules.GetRuleDetails", params);
|
||||
@ -2480,10 +2588,10 @@ void TestRules::testRuleActionParams_data()
|
||||
|
||||
QTest::newRow("valid action params") << action << QVariantMap() << RuleEngine::RuleErrorNoError;
|
||||
QTest::newRow("valid action and exit action params") << action << action << RuleEngine::RuleErrorNoError;
|
||||
QTest::newRow("invalid action params1") << invalidAction1 << QVariantMap() << RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||
QTest::newRow("invalid action params2") << invalidAction2 << QVariantMap() << RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||
QTest::newRow("valid action and invalid exit action params1") << action << invalidAction1 << RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||
QTest::newRow("valid action and invalid exit action params2") << action << invalidAction2 << RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||
QTest::newRow("invalid action params1") << invalidAction1 << QVariantMap() << RuleEngine::RuleErrorMissingParameter;
|
||||
QTest::newRow("invalid action params2") << invalidAction2 << QVariantMap() << RuleEngine::RuleErrorMissingParameter;
|
||||
QTest::newRow("valid action and invalid exit action params1") << action << invalidAction1 << RuleEngine::RuleErrorMissingParameter;
|
||||
QTest::newRow("valid action and invalid exit action params2") << action << invalidAction2 << RuleEngine::RuleErrorMissingParameter;
|
||||
}
|
||||
|
||||
void TestRules::testRuleActionParams()
|
||||
|
||||
Reference in New Issue
Block a user