mirror of https://github.com/nymea/nymea.git
Add support for state based rule action params
parent
87595faf6d
commit
774452ff7c
|
|
@ -188,6 +188,8 @@ void JsonTypes::init()
|
||||||
s_ruleActionParam.insert("o:value", basicTypeRef());
|
s_ruleActionParam.insert("o:value", basicTypeRef());
|
||||||
s_ruleActionParam.insert("o:eventTypeId", basicTypeToString(Uuid));
|
s_ruleActionParam.insert("o:eventTypeId", basicTypeToString(Uuid));
|
||||||
s_ruleActionParam.insert("o:eventParamTypeId", basicTypeToString(Uuid));
|
s_ruleActionParam.insert("o:eventParamTypeId", basicTypeToString(Uuid));
|
||||||
|
s_ruleActionParam.insert("o:deviceId", basicTypeToString(Uuid));
|
||||||
|
s_ruleActionParam.insert("o:stateTypeId", basicTypeToString(Uuid));
|
||||||
|
|
||||||
// ParamDescriptor
|
// ParamDescriptor
|
||||||
s_paramDescriptor.insert("o:paramTypeId", basicTypeToString(Uuid));
|
s_paramDescriptor.insert("o:paramTypeId", basicTypeToString(Uuid));
|
||||||
|
|
@ -612,10 +614,13 @@ QVariantMap JsonTypes::packRuleActionParam(const RuleActionParam &ruleActionPara
|
||||||
} else {
|
} else {
|
||||||
variantMap.insert("paramName", ruleActionParam.paramName());
|
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("eventTypeId", ruleActionParam.eventTypeId().toString());
|
||||||
variantMap.insert("eventParamTypeId", ruleActionParam.eventParamTypeId().toString());
|
variantMap.insert("eventParamTypeId", ruleActionParam.eventParamTypeId().toString());
|
||||||
|
} else if (ruleActionParam.isStateBased()) {
|
||||||
|
variantMap.insert("deviceId", ruleActionParam.deviceId().toString());
|
||||||
|
variantMap.insert("stateTypeId", ruleActionParam.stateTypeId().toString());
|
||||||
} else {
|
} else {
|
||||||
variantMap.insert("value", ruleActionParam.value());
|
variantMap.insert("value", ruleActionParam.value());
|
||||||
}
|
}
|
||||||
|
|
@ -1429,13 +1434,19 @@ RuleActionParam JsonTypes::unpackRuleActionParam(const QVariantMap &ruleActionPa
|
||||||
|
|
||||||
ParamTypeId paramTypeId = ParamTypeId(ruleActionParamMap.value("paramTypeId").toString());
|
ParamTypeId paramTypeId = ParamTypeId(ruleActionParamMap.value("paramTypeId").toString());
|
||||||
QString paramName = ruleActionParamMap.value("paramName").toString();
|
QString paramName = ruleActionParamMap.value("paramName").toString();
|
||||||
QVariant value = ruleActionParamMap.value("value");
|
|
||||||
EventTypeId eventTypeId = EventTypeId(ruleActionParamMap.value("eventTypeId").toString());
|
RuleActionParam param;
|
||||||
ParamTypeId eventParamTypeId = ParamTypeId(ruleActionParamMap.value("eventParamTypeId").toString());
|
|
||||||
if (paramTypeId.isNull()) {
|
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.setDeviceId(DeviceId(ruleActionParamMap.value("deviceId").toString()));
|
||||||
|
param.setStateTypeId(StateTypeId(ruleActionParamMap.value("stateTypeId").toString()));
|
||||||
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns a \l{RuleActionParamList} created from the given \a ruleActionParamList. */
|
/*! Returns a \l{RuleActionParamList} created from the given \a ruleActionParamList. */
|
||||||
|
|
|
||||||
|
|
@ -438,31 +438,85 @@ void NymeaCore::executeRuleActions(const QList<RuleAction> ruleActions)
|
||||||
QList<Action> actions;
|
QList<Action> actions;
|
||||||
foreach (const RuleAction &ruleAction, ruleActions) {
|
foreach (const RuleAction &ruleAction, ruleActions) {
|
||||||
if (ruleAction.type() == RuleAction::TypeDevice) {
|
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.deviceId());
|
||||||
|
if (!stateDevice) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.deviceId() << "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 {
|
} else {
|
||||||
QList<Device*> devices = m_deviceManager->findConfiguredDevices(ruleAction.interface());
|
QList<Device*> devices = m_deviceManager->findConfiguredDevices(ruleAction.interface());
|
||||||
foreach (Device* device, devices) {
|
foreach (Device* device, devices) {
|
||||||
DeviceClass dc = m_deviceManager->findDeviceClass(device->deviceClassId());
|
DeviceClass deviceClass = m_deviceManager->findDeviceClass(device->deviceClassId());
|
||||||
ActionType at = dc.actionTypes().findByName(ruleAction.interfaceAction());
|
ActionType actionType = deviceClass.actionTypes().findByName(ruleAction.interfaceAction());
|
||||||
if (at.id().isNull()) {
|
if (actionType.id().isNull()) {
|
||||||
qCWarning(dcRuleEngine()) << "Error creating Action. The given DeviceClass does not implement action:" << ruleAction.interfaceAction();
|
qCWarning(dcRuleEngine()) << "Error creating Action. The given DeviceClass does not implement action:" << ruleAction.interfaceAction();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Action action = Action(at.id(), device->id());
|
|
||||||
ParamList params;
|
ParamList params;
|
||||||
foreach (const RuleActionParam &rap, ruleAction.ruleActionParams()) {
|
bool ok = true;
|
||||||
ParamType pt = at.paramTypes().findByName(rap.paramName());
|
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
|
||||||
if (pt.id().isNull()) {
|
ParamType paramType = actionType.paramTypes().findByName(ruleActionParam.paramName());
|
||||||
qCWarning(dcRuleEngine()) << "Error creating Action. Failed to match interface param type to DeviceClass paramtype.";
|
if (paramType.id().isNull()) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Error creating Action. The given ActionType does not have a parameter:" << ruleActionParam.paramName();
|
||||||
|
ok = false;
|
||||||
continue;
|
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.deviceId());
|
||||||
|
if (!stateDevice) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.deviceId() << "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);
|
action.setParams(params);
|
||||||
actions.append(action);
|
actions.append(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (const Action &action, actions) {
|
foreach (const Action &action, actions) {
|
||||||
qCDebug(dcRuleEngine) << "Executing action" << action.actionTypeId() << action.params();
|
qCDebug(dcRuleEngine) << "Executing action" << action.actionTypeId() << action.params();
|
||||||
DeviceManager::DeviceError status = executeAction(action);
|
DeviceManager::DeviceError status = executeAction(action);
|
||||||
|
|
@ -652,9 +706,7 @@ void NymeaCore::gotEvent(const Event &event)
|
||||||
foreach (RuleActionParam ruleActionParam, ruleAction.ruleActionParams()) {
|
foreach (RuleActionParam ruleActionParam, ruleAction.ruleActionParams()) {
|
||||||
// if this event param should be taken over in this action
|
// if this event param should be taken over in this action
|
||||||
if (event.eventTypeId() == ruleActionParam.eventTypeId()) {
|
if (event.eventTypeId() == ruleActionParam.eventTypeId()) {
|
||||||
QVariant eventValue = event.params().first().value();
|
QVariant eventValue = event.params().paramValue(ruleActionParam.eventParamTypeId());
|
||||||
|
|
||||||
// TODO: get param names...when an event has more than one parameter
|
|
||||||
|
|
||||||
// TODO: limits / scale calculation -> actionValue = eventValue * x
|
// TODO: limits / scale calculation -> actionValue = eventValue * x
|
||||||
// something like a EventParamDescriptor
|
// something like a EventParamDescriptor
|
||||||
|
|
|
||||||
|
|
@ -401,55 +401,6 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
||||||
return RuleErrorActionTypeNotFound;
|
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
|
} else { // Is TypeInterface
|
||||||
Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(action.interface());
|
Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(action.interface());
|
||||||
if (!iface.isValid()) {
|
if (!iface.isValid()) {
|
||||||
|
|
@ -471,77 +422,145 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
||||||
return RuleError::RuleErrorInvalidParameter;
|
return RuleError::RuleErrorInvalidParameter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Check params
|
}
|
||||||
|
|
||||||
|
foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) {
|
||||||
|
if (ruleActionParam.isEventBased()) {
|
||||||
|
// We have an eventTypeId, see if the rule actually has such a event
|
||||||
|
if (rule.eventDescriptors().isEmpty() || !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(static_cast<int>(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 if (ruleActionParam.isStateBased()) {
|
||||||
|
Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.deviceId());
|
||||||
|
if (!d) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleAction" << action.actionTypeId() << "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(action.actionTypeId(), 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 {
|
||||||
|
if (ruleActionParam.value().isNull()) {
|
||||||
|
qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString();
|
||||||
|
return RuleErrorInvalidRuleActionParameter;
|
||||||
|
}
|
||||||
|
QVariant::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId());
|
||||||
|
if (ruleActionParam.value().type() != actionParamType && !ruleActionParam.value().canConvert(static_cast<int>(actionParamType))) {
|
||||||
|
qCDebug(dcRuleEngine()) << "Cannot create rule. Given param value for action" << ruleActionParam.paramTypeId().toString() << "does not match type";
|
||||||
|
return RuleErrorInvalidRuleActionParameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) {
|
||||||
|
if (!ruleActionParam.isValid()) {
|
||||||
|
qCWarning(dcRuleEngine) << "Cannot create rule. There must be only one out of \"value\", \"eventTypeId/eventParamTypeID\" or \"deviceId/stateTypeId\".";
|
||||||
|
return RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check exit actions
|
// Check exit actions
|
||||||
foreach (const RuleAction &ruleAction, rule.exitActions()) {
|
foreach (const RuleAction &ruleExitAction, rule.exitActions()) {
|
||||||
if (!ruleAction.isValid()) {
|
if (!ruleExitAction.isValid()) {
|
||||||
qWarning(dcRuleEngine()) << "Exit Action is incomplete. It must have either actionTypeId and deviceId, or interface and interfaceAction";
|
qWarning(dcRuleEngine()) << "Exit Action is incomplete. It must have either actionTypeId and deviceId, or interface and interfaceAction";
|
||||||
return RuleErrorActionTypeNotFound;
|
return RuleErrorActionTypeNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ruleAction.type() == RuleAction::TypeDevice) {
|
if (ruleExitAction.type() == RuleAction::TypeDevice) {
|
||||||
Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleAction.deviceId());
|
Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleExitAction.deviceId());
|
||||||
if (!device) {
|
if (!device) {
|
||||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for exit action with actionTypeId" << ruleAction.actionTypeId();
|
qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for exit action with actionTypeId" << ruleExitAction.actionTypeId();
|
||||||
return RuleErrorDeviceNotFound;
|
return RuleErrorDeviceNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
||||||
if (!deviceClass.hasActionType(ruleAction.actionTypeId())) {
|
if (!deviceClass.hasActionType(ruleExitAction.actionTypeId())) {
|
||||||
qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << ruleAction.actionTypeId();
|
qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << ruleExitAction.actionTypeId();
|
||||||
return RuleErrorActionTypeNotFound;
|
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
|
} else { // Is TypeInterface
|
||||||
Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(ruleAction.interface());
|
Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(ruleExitAction.interface());
|
||||||
if (!iface.isValid()) {
|
if (!iface.isValid()) {
|
||||||
qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleAction.interface();
|
qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleExitAction.interface();
|
||||||
return RuleError::RuleErrorInterfaceNotFound;
|
return RuleError::RuleErrorInterfaceNotFound;
|
||||||
}
|
}
|
||||||
ActionType ifaceActionType = iface.actionTypes().findByName(ruleAction.interfaceAction());
|
ActionType ifaceActionType = iface.actionTypes().findByName(ruleExitAction.interfaceAction());
|
||||||
if (ifaceActionType.name().isEmpty()) {
|
if (ifaceActionType.name().isEmpty()) {
|
||||||
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << ruleAction.interfaceAction();
|
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << ruleExitAction.interfaceAction();
|
||||||
return RuleError::RuleErrorActionTypeNotFound;
|
return RuleError::RuleErrorActionTypeNotFound;
|
||||||
}
|
}
|
||||||
foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) {
|
foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) {
|
||||||
if (!ruleAction.ruleActionParams().hasParam(ifaceActionParamType.name())) {
|
if (!ruleExitAction.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());
|
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << ruleExitAction.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(ifaceActionParamType.type());
|
||||||
return RuleError::RuleErrorMissingParameter;
|
return RuleError::RuleErrorMissingParameter;
|
||||||
}
|
}
|
||||||
if (!ruleAction.ruleActionParam(ifaceActionParamType.name()).value().canConvert(ifaceActionParamType.type())) {
|
if (!ruleExitAction.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());
|
qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << ruleExitAction.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(ifaceActionParamType.type());
|
||||||
return RuleError::RuleErrorInvalidParameter;
|
return RuleError::RuleErrorInvalidParameter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Check params
|
}
|
||||||
|
|
||||||
|
foreach (const RuleActionParam &ruleActionParam, ruleExitAction.ruleActionParams()) {
|
||||||
|
if (ruleActionParam.isEventBased()) {
|
||||||
|
// We have an eventTypeId, see if the rule actually has such a event
|
||||||
|
qCWarning(dcRuleEngine) << "Cannot create rule. Exit actions cannot be event based.";
|
||||||
|
return RuleErrorInvalidRuleActionParameter;
|
||||||
|
} else if (ruleActionParam.isStateBased()) {
|
||||||
|
Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.deviceId());
|
||||||
|
if (!d) {
|
||||||
|
qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleAction" << ruleExitAction.actionTypeId() << "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(ruleExitAction.actionTypeId(), 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 {
|
||||||
|
if (ruleActionParam.value().isNull()) {
|
||||||
|
qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString();
|
||||||
|
return RuleErrorInvalidRuleActionParameter;
|
||||||
|
}
|
||||||
|
QVariant::Type actionParamType = getActionParamType(ruleExitAction.actionTypeId(), ruleActionParam.paramTypeId());
|
||||||
|
if (ruleActionParam.value().type() != actionParamType && !ruleActionParam.value().canConvert(static_cast<int>(actionParamType))) {
|
||||||
|
qCDebug(dcRuleEngine()) << "Cannot create rule. Given param value for action" << ruleActionParam.paramTypeId().toString() << "does not match type";
|
||||||
|
return RuleErrorInvalidRuleActionParameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (const RuleActionParam &ruleActionParam, ruleExitAction.ruleActionParams()) {
|
||||||
|
if (!ruleActionParam.isValid()) {
|
||||||
|
qCWarning(dcRuleEngine) << "Cannot create rule. There must be only one out of \"value\", \"eventTypeId/eventParamTypeID\" or \"deviceId/stateTypeId\".";
|
||||||
|
return RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -698,9 +717,9 @@ RuleEngine::RuleError RuleEngine::disableRule(const RuleId &ruleId)
|
||||||
*/
|
*/
|
||||||
RuleEngine::RuleError RuleEngine::executeActions(const RuleId &ruleId)
|
RuleEngine::RuleError RuleEngine::executeActions(const RuleId &ruleId)
|
||||||
{
|
{
|
||||||
// check if rule exits
|
// check if rule exists
|
||||||
if (!m_rules.contains(ruleId)) {
|
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;
|
return RuleErrorRuleNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1203,11 +1222,14 @@ void RuleEngine::saveRule(const Rule &rule)
|
||||||
} else {
|
} else {
|
||||||
settings.beginGroup("RuleActionParam-" + param.paramName());
|
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.setValue("value", param.value());
|
||||||
if (param.eventTypeId() != EventTypeId()) {
|
if (param.isEventBased()) {
|
||||||
settings.setValue("eventTypeId", param.eventTypeId().toString());
|
settings.setValue("eventTypeId", param.eventTypeId().toString());
|
||||||
settings.setValue("eventParamTypeId", param.eventParamTypeId());
|
settings.setValue("eventParamTypeId", param.eventParamTypeId());
|
||||||
|
} else if (param.isStateBased()) {
|
||||||
|
settings.setValue("deviceId", param.deviceId().toString());
|
||||||
|
settings.setValue("stateTypeId", param.stateTypeId());
|
||||||
}
|
}
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
@ -1276,7 +1298,7 @@ void RuleEngine::init()
|
||||||
|
|
||||||
QList<int> weekDays;
|
QList<int> weekDays;
|
||||||
QList<int> monthDays;
|
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
|
// Load weekDays
|
||||||
int weekDaysCount = settings.beginReadArray("weekDays");
|
int weekDaysCount = settings.beginReadArray("weekDays");
|
||||||
|
|
@ -1313,7 +1335,7 @@ void RuleEngine::init()
|
||||||
|
|
||||||
QList<int> weekDays;
|
QList<int> weekDays;
|
||||||
QList<int> monthDays;
|
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
|
// Load weekDays
|
||||||
int weekDaysCount = settings.beginReadArray("weekDays");
|
int weekDaysCount = settings.beginReadArray("weekDays");
|
||||||
|
|
@ -1414,6 +1436,8 @@ void RuleEngine::init()
|
||||||
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-"));
|
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-"));
|
||||||
EventTypeId eventTypeId = EventTypeId(settings.value("eventTypeId", EventTypeId()).toString());
|
EventTypeId eventTypeId = EventTypeId(settings.value("eventTypeId", EventTypeId()).toString());
|
||||||
ParamTypeId eventParamTypeId = ParamTypeId(settings.value("eventParamTypeId", ParamTypeId()).toString());
|
ParamTypeId eventParamTypeId = ParamTypeId(settings.value("eventParamTypeId", ParamTypeId()).toString());
|
||||||
|
DeviceId deviceId = DeviceId(settings.value("deviceId", DeviceId()).toString());
|
||||||
|
StateTypeId stateTypeId = StateTypeId(settings.value("stateTypeId", StateTypeId()).toString());
|
||||||
QVariant value = settings.value("value");
|
QVariant value = settings.value("value");
|
||||||
if (settings.contains("valueType")) {
|
if (settings.contains("valueType")) {
|
||||||
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
|
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
|
||||||
|
|
@ -1427,19 +1451,20 @@ void RuleEngine::init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RuleActionParam param;
|
||||||
if (!ParamTypeId(strippedParamTypeIdString).isNull()) {
|
if (!ParamTypeId(strippedParamTypeIdString).isNull()) {
|
||||||
RuleActionParam param(ParamTypeId(strippedParamTypeIdString),
|
// By ParamTypeId
|
||||||
value,
|
param = RuleActionParam(ParamTypeId(strippedParamTypeIdString), value);
|
||||||
eventTypeId,
|
|
||||||
eventParamTypeId);
|
|
||||||
params.append(param);
|
|
||||||
} else {
|
} else {
|
||||||
RuleActionParam param(strippedParamTypeIdString,
|
// By param name
|
||||||
value,
|
param = RuleActionParam(strippedParamTypeIdString, value);
|
||||||
eventTypeId,
|
|
||||||
eventParamTypeId);
|
|
||||||
params.append(param);
|
|
||||||
}
|
}
|
||||||
|
param.setEventTypeId(eventTypeId);
|
||||||
|
param.setEventParamTypeId(eventParamTypeId);
|
||||||
|
param.setDeviceId(deviceId);
|
||||||
|
param.setStateTypeId(stateTypeId);
|
||||||
|
params.append(param);
|
||||||
|
params.append(param);
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ QDateTime TimeEventItem::dateTime() const
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Sets the dateTime of this \l{TimeEventItem} to the given \a timeStamp. */
|
/*! 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);
|
m_dateTime = QDateTime::fromTime_t(timeStamp);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public:
|
||||||
TimeEventItem();
|
TimeEventItem();
|
||||||
|
|
||||||
QDateTime dateTime() const;
|
QDateTime dateTime() const;
|
||||||
void setDateTime(const int &timeStamp);
|
void setDateTime(const uint &timeStamp);
|
||||||
|
|
||||||
QTime time() const;
|
QTime time() const;
|
||||||
void setTime(const QTime &time);
|
void setTime(const QTime &time);
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,17 @@ RuleAction::Type RuleAction::type() const
|
||||||
bool RuleAction::isEventBased() const
|
bool RuleAction::isEventBased() const
|
||||||
{
|
{
|
||||||
foreach (const RuleActionParam ¶m, m_ruleActionParams) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +177,7 @@ RuleActionParam RuleAction::ruleActionParam(const ParamTypeId &ruleActionParamTy
|
||||||
return ruleActionParam;
|
return ruleActionParam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RuleActionParam(QString());
|
return RuleActionParam();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns the \l{RuleActionParam} of this RuleAction with the given \a ruleActionParamName.
|
/*! 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RuleActionParam(QString());
|
return RuleActionParam();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Copy the data to a \l{RuleAction} from an \a other rule action. */
|
/*! Copy the data to a \l{RuleAction} from an \a other rule action. */
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ public:
|
||||||
Type type() const;
|
Type type() const;
|
||||||
|
|
||||||
bool isEventBased() const;
|
bool isEventBased() const;
|
||||||
|
bool isStateBased() const;
|
||||||
|
|
||||||
Action toAction() const;
|
Action toAction() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,21 @@
|
||||||
A RuleActionParam allows rules to take over an \l{Event} parameter into a rule
|
A RuleActionParam allows rules to take over an \l{Event} parameter into a rule
|
||||||
\l{RuleAction}.
|
\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,
|
\sa nymeaserver::Rule, RuleAction,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -41,33 +56,68 @@
|
||||||
* \sa Param, */
|
* \sa Param, */
|
||||||
RuleActionParam::RuleActionParam(const Param ¶m) :
|
RuleActionParam::RuleActionParam(const Param ¶m) :
|
||||||
m_paramTypeId(param.paramTypeId()),
|
m_paramTypeId(param.paramTypeId()),
|
||||||
m_value(param.value()),
|
m_value(param.value())
|
||||||
m_eventTypeId(EventTypeId()),
|
|
||||||
m_eventParamTypeId(ParamTypeId())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! 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, */
|
* \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_paramTypeId(paramTypeId),
|
||||||
m_value(value),
|
|
||||||
m_eventTypeId(eventTypeId),
|
m_eventTypeId(eventTypeId),
|
||||||
m_eventParamTypeId(eventParamTypeId)
|
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 deviceId and \a stateTypeId.
|
||||||
* \sa Param, Event, */
|
* \sa Param, Event, */
|
||||||
RuleActionParam::RuleActionParam(const QString ¶mName, const QVariant &value, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId):
|
RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &deviceId, const StateTypeId &stateTypeId):
|
||||||
|
m_paramTypeId(paramTypeId),
|
||||||
|
m_deviceId(deviceId),
|
||||||
|
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_paramName(paramName),
|
||||||
m_value(value),
|
|
||||||
m_eventTypeId(eventTypeId),
|
m_eventTypeId(eventTypeId),
|
||||||
m_eventParamTypeId(eventParamTypeId)
|
m_eventParamTypeId(eventParamTypeId)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a deviceId and \a stateTypeId.
|
||||||
|
* \sa Param, Event, */
|
||||||
|
RuleActionParam::RuleActionParam(const QString ¶mName, const DeviceId &deviceId, const StateTypeId &stateTypeId):
|
||||||
|
m_paramName(paramName),
|
||||||
|
m_deviceId(deviceId),
|
||||||
|
m_stateTypeId(stateTypeId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*! Returns the \l ParamTypeId of this \l RuleActionParam. */
|
/*! Returns the \l ParamTypeId of this \l RuleActionParam. */
|
||||||
ParamTypeId RuleActionParam::paramTypeId() const
|
ParamTypeId RuleActionParam::paramTypeId() const
|
||||||
{
|
{
|
||||||
|
|
@ -80,18 +130,6 @@ QString RuleActionParam::paramName() const
|
||||||
return m_paramName;
|
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. */
|
/*! Returns the value of this RuleActionParam. */
|
||||||
QVariant RuleActionParam::value() const
|
QVariant RuleActionParam::value() const
|
||||||
{
|
{
|
||||||
|
|
@ -104,14 +142,6 @@ void RuleActionParam::setValue(const QVariant &value)
|
||||||
m_value = 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}. */
|
/*! Return the EventTypeId of the \l{Event} with the \l{Param} which will be taken over in the \l{RuleAction}. */
|
||||||
EventTypeId RuleActionParam::eventTypeId() const
|
EventTypeId RuleActionParam::eventTypeId() const
|
||||||
{
|
{
|
||||||
|
|
@ -124,6 +154,66 @@ void RuleActionParam::setEventTypeId(const EventTypeId &eventTypeId)
|
||||||
m_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::deviceId() const
|
||||||
|
{
|
||||||
|
return m_deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Sets the deviceId identifying the device to use a state value from. */
|
||||||
|
void RuleActionParam::setDeviceId(const DeviceId &deviceId)
|
||||||
|
{
|
||||||
|
m_deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! 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_deviceId.isNull() && !m_stateTypeId.isNull();
|
||||||
|
}
|
||||||
|
|
||||||
/*! Writes the paramTypeId, value, eventId and eventParamTypeId of the given \a ruleActionParam to \a dbg. */
|
/*! Writes the paramTypeId, value, eventId and eventParamTypeId of the given \a ruleActionParam to \a dbg. */
|
||||||
QDebug operator<<(QDebug dbg, const RuleActionParam &ruleActionParam)
|
QDebug operator<<(QDebug dbg, const RuleActionParam &ruleActionParam)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,29 +36,46 @@ class LIBNYMEA_EXPORT RuleActionParam
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RuleActionParam(const Param ¶m = Param());
|
RuleActionParam(const Param ¶m = Param());
|
||||||
RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant(), const EventTypeId &eventTypeId = EventTypeId(), const ParamTypeId &eventParamTypeId = ParamTypeId());
|
RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant());
|
||||||
RuleActionParam(const QString ¶mName, const QVariant &value = QVariant(), const EventTypeId &eventTypeId = EventTypeId(), const ParamTypeId &eventParamTypeId = ParamTypeId());
|
RuleActionParam(const ParamTypeId ¶mTypeId, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId);
|
||||||
|
RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &deviceId, 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 &deviceId, const StateTypeId &stateTypeId);
|
||||||
|
|
||||||
ParamTypeId paramTypeId() const;
|
ParamTypeId paramTypeId() const;
|
||||||
QString paramName() const;
|
QString paramName() const;
|
||||||
|
|
||||||
ParamTypeId eventParamTypeId() const;
|
bool isValid() const;
|
||||||
void setEventParamTypeId(const ParamTypeId &eventParamTypeId);
|
bool isValueBased() const;
|
||||||
|
bool isEventBased() const;
|
||||||
|
bool isStateBased() const;
|
||||||
|
|
||||||
QVariant value() const;
|
QVariant value() const;
|
||||||
void setValue(const QVariant &value);
|
void setValue(const QVariant &value);
|
||||||
|
|
||||||
bool isValid() const;
|
|
||||||
|
|
||||||
EventTypeId eventTypeId() const;
|
EventTypeId eventTypeId() const;
|
||||||
void setEventTypeId(const EventTypeId &eventTypeId);
|
void setEventTypeId(const EventTypeId &eventTypeId);
|
||||||
|
|
||||||
|
ParamTypeId eventParamTypeId() const;
|
||||||
|
void setEventParamTypeId(const ParamTypeId &eventParamTypeId);
|
||||||
|
|
||||||
|
DeviceId deviceId() const;
|
||||||
|
void setDeviceId(const DeviceId &deviceId);
|
||||||
|
|
||||||
|
StateTypeId stateTypeId() const;
|
||||||
|
void setStateTypeId(const StateTypeId &stateTypeId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ParamTypeId m_paramTypeId;
|
ParamTypeId m_paramTypeId;
|
||||||
QString m_paramName;
|
QString m_paramName;
|
||||||
QVariant m_value;
|
QVariant m_value;
|
||||||
|
|
||||||
EventTypeId m_eventTypeId;
|
EventTypeId m_eventTypeId;
|
||||||
ParamTypeId m_eventParamTypeId;
|
ParamTypeId m_eventParamTypeId;
|
||||||
|
|
||||||
|
DeviceId m_deviceId;
|
||||||
|
StateTypeId m_stateTypeId;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(RuleActionParam)
|
Q_DECLARE_METATYPE(RuleActionParam)
|
||||||
|
|
|
||||||
|
|
@ -93,9 +93,10 @@ private slots:
|
||||||
void enableDisableRule();
|
void enableDisableRule();
|
||||||
|
|
||||||
void testEventBasedAction();
|
void testEventBasedAction();
|
||||||
|
|
||||||
void testEventBasedRuleWithExitAction();
|
void testEventBasedRuleWithExitAction();
|
||||||
|
|
||||||
|
void testStateBasedAction();
|
||||||
|
|
||||||
void removePolicyUpdate();
|
void removePolicyUpdate();
|
||||||
void removePolicyCascade();
|
void removePolicyCascade();
|
||||||
void removePolicyUpdateRendersUselessRule();
|
void removePolicyUpdateRendersUselessRule();
|
||||||
|
|
@ -2214,6 +2215,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("deviceId", m_mockDeviceId);
|
||||||
|
param1.insert("stateTypeId", mockIntStateId);
|
||||||
|
QVariantMap param2;
|
||||||
|
param2.insert("paramTypeId", mockActionParam2ParamTypeId);
|
||||||
|
param2.insert("deviceId", 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);
|
||||||
|
|
||||||
|
qDebug() << addRuleParams;
|
||||||
|
|
||||||
|
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()
|
void TestRules::removePolicyUpdate()
|
||||||
{
|
{
|
||||||
// ADD parent device
|
// ADD parent device
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue