mirror of https://github.com/nymea/nymea.git
add support for interface based rules
parent
57d4466f9a
commit
58c83e9072
2
guh.pri
2
guh.pri
|
|
@ -6,7 +6,7 @@ GUH_PLUGINS_PATH=/usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH')/gu
|
|||
|
||||
# define protocol versions
|
||||
JSON_PROTOCOL_VERSION_MAJOR=1
|
||||
JSON_PROTOCOL_VERSION_MINOR=0
|
||||
JSON_PROTOCOL_VERSION_MINOR=1
|
||||
REST_API_VERSION=1
|
||||
|
||||
DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\" \
|
||||
|
|
|
|||
|
|
@ -338,9 +338,36 @@ DeviceManager::DeviceError GuhCore::executeAction(const Action &action)
|
|||
/*! Execute the given \a ruleActions. */
|
||||
void GuhCore::executeRuleActions(const QList<RuleAction> ruleActions)
|
||||
{
|
||||
QList<Action> actions;
|
||||
foreach (const RuleAction &ruleAction, ruleActions) {
|
||||
Action action = ruleAction.toAction();
|
||||
qCDebug(dcRuleEngine) << "Executing action" << ruleAction.actionTypeId() << action.params();
|
||||
if (ruleAction.type() == RuleAction::TypeDevice) {
|
||||
actions.append(ruleAction.toAction());
|
||||
} 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()) {
|
||||
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.";
|
||||
continue;
|
||||
}
|
||||
params.append(Param(pt.id(), rap.value()));
|
||||
}
|
||||
action.setParams(params);
|
||||
actions.append(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (const Action &action, actions) {
|
||||
qCDebug(dcRuleEngine) << "Executing action" << action.actionTypeId() << action.params();
|
||||
DeviceManager::DeviceError status = executeAction(action);
|
||||
switch(status) {
|
||||
case DeviceManager::DeviceErrorNoError:
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
|
||||
#include "rule.h"
|
||||
#include "types/event.h"
|
||||
#include "types/deviceclass.h"
|
||||
#include "plugin/deviceplugin.h"
|
||||
#include "plugin/deviceclass.h"
|
||||
#include "plugin/devicedescriptor.h"
|
||||
|
||||
#include "logging/logengine.h"
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@
|
|||
#include "guhcore.h"
|
||||
#include "devicemanager.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "types/deviceclass.h"
|
||||
#include "plugin/device.h"
|
||||
#include "plugin/deviceclass.h"
|
||||
#include "plugin/deviceplugin.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
#include "guhcore.h"
|
||||
#include "devicemanager.h"
|
||||
#include "plugin/deviceplugin.h"
|
||||
#include "plugin/deviceclass.h"
|
||||
#include "types/deviceclass.h"
|
||||
#include "plugin/device.h"
|
||||
#include "rule.h"
|
||||
#include "ruleengine.h"
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@
|
|||
#ifndef JSONRPCSERVER_H
|
||||
#define JSONRPCSERVER_H
|
||||
|
||||
#include "plugin/deviceclass.h"
|
||||
#include "jsonhandler.h"
|
||||
#include "transportinterface.h"
|
||||
#include "usermanager.h"
|
||||
|
||||
#include "types/deviceclass.h"
|
||||
#include "types/action.h"
|
||||
#include "types/event.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -168,12 +168,15 @@ void JsonTypes::init()
|
|||
s_param.insert("value", basicTypeRef());
|
||||
|
||||
// RuleAction
|
||||
s_ruleAction.insert("actionTypeId", basicTypeToString(Uuid));
|
||||
s_ruleAction.insert("deviceId", basicTypeToString(Uuid));
|
||||
s_ruleAction.insert("o:deviceId", basicTypeToString(Uuid));
|
||||
s_ruleAction.insert("o:actionTypeId", basicTypeToString(Uuid));
|
||||
s_ruleAction.insert("o:interface", basicTypeToString(String));
|
||||
s_ruleAction.insert("o:interfaceAction", basicTypeToString(String));
|
||||
s_ruleAction.insert("o:ruleActionParams", QVariantList() << ruleActionParamRef());
|
||||
|
||||
// RuleActionParam
|
||||
s_ruleActionParam.insert("paramTypeId", basicTypeToString(Uuid));
|
||||
s_ruleActionParam.insert("o:paramTypeId", basicTypeToString(Uuid));
|
||||
s_ruleActionParam.insert("o:paramName", basicTypeToString(String));
|
||||
s_ruleActionParam.insert("o:value", basicTypeRef());
|
||||
s_ruleActionParam.insert("o:eventTypeId", basicTypeToString(Uuid));
|
||||
s_ruleActionParam.insert("o:eventParamTypeId", basicTypeToString(Uuid));
|
||||
|
|
@ -228,8 +231,10 @@ void JsonTypes::init()
|
|||
s_event.insert("o:params", QVariantList() << paramRef());
|
||||
|
||||
// EventDescriptor
|
||||
s_eventDescriptor.insert("eventTypeId", basicTypeToString(Uuid));
|
||||
s_eventDescriptor.insert("deviceId", basicTypeToString(Uuid));
|
||||
s_eventDescriptor.insert("o:eventTypeId", basicTypeToString(Uuid));
|
||||
s_eventDescriptor.insert("o:deviceId", basicTypeToString(Uuid));
|
||||
s_eventDescriptor.insert("o:interface", basicTypeToString(String));
|
||||
s_eventDescriptor.insert("o:interfaceEvent", basicTypeToString(String));
|
||||
s_eventDescriptor.insert("o:paramDescriptors", QVariantList() << paramDescriptorRef());
|
||||
|
||||
// ActionType
|
||||
|
|
@ -1320,10 +1325,16 @@ Rule JsonTypes::unpackRule(const QVariantMap &ruleMap)
|
|||
/*! Returns a \l{RuleAction} created from the given \a ruleActionMap. */
|
||||
RuleAction JsonTypes::unpackRuleAction(const QVariantMap &ruleActionMap)
|
||||
{
|
||||
RuleAction action(ActionTypeId(ruleActionMap.value("actionTypeId").toString()), DeviceId(ruleActionMap.value("deviceId").toString()));
|
||||
ActionTypeId actionTypeId(ruleActionMap.value("actionTypeId").toString());
|
||||
DeviceId actionDeviceId(ruleActionMap.value("deviceId").toString());
|
||||
QString interface = ruleActionMap.value("interface").toString();
|
||||
QString interfaceAction = ruleActionMap.value("interfaceAction").toString();
|
||||
RuleActionParamList actionParamList = JsonTypes::unpackRuleActionParams(ruleActionMap.value("ruleActionParams").toList());
|
||||
action.setRuleActionParams(actionParamList);
|
||||
return action;
|
||||
|
||||
if (!actionTypeId.isNull() && !actionDeviceId.isNull()) {
|
||||
return RuleAction(actionTypeId, actionDeviceId, actionParamList);
|
||||
}
|
||||
return RuleAction(interface, interfaceAction, actionParamList);
|
||||
}
|
||||
|
||||
/*! Returns a \l{RuleActionParam} created from the given \a ruleActionParamMap. */
|
||||
|
|
@ -1333,9 +1344,13 @@ RuleActionParam JsonTypes::unpackRuleActionParam(const QVariantMap &ruleActionPa
|
|||
return RuleActionParam();
|
||||
|
||||
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());
|
||||
if (paramTypeId.isNull()) {
|
||||
return RuleActionParam(paramName, value, eventTypeId, eventParamTypeId);
|
||||
}
|
||||
return RuleActionParam(paramTypeId, value, eventTypeId, eventParamTypeId);
|
||||
}
|
||||
|
||||
|
|
@ -1377,9 +1392,13 @@ EventDescriptor JsonTypes::unpackEventDescriptor(const QVariantMap &eventDescrip
|
|||
{
|
||||
EventTypeId eventTypeId(eventDescriptorMap.value("eventTypeId").toString());
|
||||
DeviceId eventDeviceId(eventDescriptorMap.value("deviceId").toString());
|
||||
QString interface = eventDescriptorMap.value("interface").toString();
|
||||
QString interfaceEvent = eventDescriptorMap.value("interfaceEvent").toString();
|
||||
QList<ParamDescriptor> eventParams = JsonTypes::unpackParamDescriptors(eventDescriptorMap.value("paramDescriptors").toList());
|
||||
EventDescriptor eventDescriptor(eventTypeId, eventDeviceId, eventParams);
|
||||
return eventDescriptor;
|
||||
if (!eventDeviceId.isNull() && !eventTypeId.isNull()) {
|
||||
return EventDescriptor(eventTypeId, eventDeviceId, eventParams);
|
||||
}
|
||||
return EventDescriptor(interface, interfaceEvent, eventParams);
|
||||
}
|
||||
|
||||
/*! Returns a \l{StateEvaluator} created from the given \a stateEvaluatorMap. */
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#ifndef JSONTYPES_H
|
||||
#define JSONTYPES_H
|
||||
|
||||
#include "plugin/deviceclass.h"
|
||||
#include "plugin/devicedescriptor.h"
|
||||
#include "rule.h"
|
||||
#include "devicemanager.h"
|
||||
|
|
@ -31,6 +30,7 @@
|
|||
#include "guhconfiguration.h"
|
||||
#include "usermanager.h"
|
||||
|
||||
#include "types/deviceclass.h"
|
||||
#include "types/event.h"
|
||||
#include "types/action.h"
|
||||
#include "types/actiontype.h"
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ QList<Rule> RuleEngine::evaluateEvent(const Event &event)
|
|||
}
|
||||
} else {
|
||||
// Event based rule
|
||||
if (containsEvent(rule, event) && rule.statesActive() && rule.timeActive()) {
|
||||
if (containsEvent(rule, event, device->deviceClassId()) && rule.statesActive() && rule.timeActive()) {
|
||||
qCDebug(dcRuleEngine) << "Rule" << rule.id() << "contains event" << event.eventId() << "and all states match.";
|
||||
rules.append(rule);
|
||||
}
|
||||
|
|
@ -465,25 +465,42 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
|||
|
||||
// Check IDs in each EventDescriptor
|
||||
foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) {
|
||||
// check deviceId
|
||||
Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(eventDescriptor.deviceId());
|
||||
if (!device) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for eventTypeId" << eventDescriptor.eventTypeId();
|
||||
return RuleErrorDeviceNotFound;
|
||||
}
|
||||
|
||||
// Check eventTypeId for this deivce
|
||||
DeviceClass deviceClass = GuhCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
||||
bool eventTypeFound = false;
|
||||
foreach (const EventType &eventType, deviceClass.eventTypes()) {
|
||||
if (eventType.id() == eventDescriptor.eventTypeId()) {
|
||||
eventTypeFound = true;
|
||||
}
|
||||
}
|
||||
if (!eventTypeFound) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no event type:" << eventDescriptor.eventTypeId();
|
||||
if (!eventDescriptor.isValid()) {
|
||||
qWarning(dcRuleEngine()) << "EventDescriptor is incomplete. It must have either eventTypeId and deviceId, or interface and interfaceEvent";
|
||||
return RuleErrorEventTypeNotFound;
|
||||
}
|
||||
if (eventDescriptor.type() == EventDescriptor::TypeDevice) {
|
||||
// check deviceId
|
||||
Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(eventDescriptor.deviceId());
|
||||
if (!device) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for eventTypeId" << eventDescriptor.eventTypeId();
|
||||
return RuleErrorDeviceNotFound;
|
||||
}
|
||||
|
||||
// Check eventTypeId for this deivce
|
||||
DeviceClass deviceClass = GuhCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
||||
bool eventTypeFound = false;
|
||||
foreach (const EventType &eventType, deviceClass.eventTypes()) {
|
||||
if (eventType.id() == eventDescriptor.eventTypeId()) {
|
||||
eventTypeFound = true;
|
||||
}
|
||||
}
|
||||
if (!eventTypeFound) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no event type:" << eventDescriptor.eventTypeId();
|
||||
return RuleErrorEventTypeNotFound;
|
||||
}
|
||||
} else {
|
||||
// Interface based event
|
||||
Interface iface = GuhCore::instance()->deviceManager()->supportedInterfaces().findByName(eventDescriptor.interface());
|
||||
if (!iface.isValid()) {
|
||||
qWarning(dcRuleEngine()) << "No such interface:" << eventDescriptor.interface();
|
||||
return RuleErrorInterfaceNotFound;
|
||||
}
|
||||
if (iface.eventTypes().findByName(eventDescriptor.interfaceEvent()).name().isEmpty()) {
|
||||
qWarning(dcRuleEngine()) << "Interface" << iface.name() << "has no such event:" << eventDescriptor.interfaceEvent();
|
||||
return RuleErrorEventTypeNotFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check state evaluator
|
||||
|
|
@ -536,104 +553,165 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit)
|
|||
|
||||
// Check actions
|
||||
foreach (const RuleAction &action, rule.actions()) {
|
||||
Device *device = GuhCore::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 = GuhCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
||||
if (!deviceClass.hasActionType(action.actionTypeId())) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << action.actionTypeId();
|
||||
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 = GuhCore::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 = GuhCore::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::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId());
|
||||
if (eventParamType != 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 = GuhCore::instance()->deviceManager()->verifyParams(actionType.paramTypes(), finalParams);
|
||||
if (paramCheck != DeviceManager::DeviceErrorNoError) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got an invalid actionParam.";
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId());
|
||||
if (eventParamType != 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;
|
||||
}
|
||||
if (!ruleActionParam.isValid()) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got an actionParam with \"value\" AND \"eventTypeId\".";
|
||||
return RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// verify action params
|
||||
foreach (const ActionType &actionType, deviceClass.actionTypes()) {
|
||||
if (actionType.id() == action.actionTypeId()) {
|
||||
ParamList finalParams = action.toAction().params();
|
||||
DeviceManager::DeviceError paramCheck = GuhCore::instance()->deviceManager()->verifyParams(actionType.paramTypes(), finalParams);
|
||||
if (paramCheck != DeviceManager::DeviceErrorNoError) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got an invalid actionParam.";
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
|
||||
} else { // Is TypeInterface
|
||||
Interface iface = GuhCore::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()) {
|
||||
qWarning() << "iface requires param:" << ifaceActionParamType.name();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) {
|
||||
if (!ruleActionParam.isValid()) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got an actionParam with \"value\" AND \"eventTypeId\".";
|
||||
return RuleEngine::RuleErrorInvalidRuleActionParameter;
|
||||
}
|
||||
// TODO: Check params
|
||||
}
|
||||
}
|
||||
|
||||
// Check exit actions
|
||||
foreach (const RuleAction &action, rule.exitActions()) {
|
||||
Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(action.deviceId());
|
||||
if (!device) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for exit action with actionTypeId" << action.actionTypeId();
|
||||
return RuleErrorDeviceNotFound;
|
||||
}
|
||||
|
||||
DeviceClass deviceClass = GuhCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
||||
if (!deviceClass.hasActionType(action.actionTypeId())) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << action.actionTypeId();
|
||||
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;
|
||||
}
|
||||
|
||||
// verify action params
|
||||
foreach (const ActionType &actionType, deviceClass.actionTypes()) {
|
||||
if (actionType.id() == action.actionTypeId()) {
|
||||
ParamList finalParams = action.toAction().params();
|
||||
DeviceManager::DeviceError paramCheck = GuhCore::instance()->deviceManager()->verifyParams(actionType.paramTypes(), finalParams);
|
||||
if (paramCheck != DeviceManager::DeviceErrorNoError) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got an invalid exit actionParam.";
|
||||
return RuleErrorInvalidRuleActionParameter;
|
||||
if (ruleAction.type() == RuleAction::TypeDevice) {
|
||||
Device *device = GuhCore::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 = GuhCore::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 = GuhCore::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 (action.isEventBased()) {
|
||||
qCWarning(dcRuleEngine) << "Cannot create rule. Got exitAction with an actionParam containing an eventTypeId. ";
|
||||
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;
|
||||
// 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 = GuhCore::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()) {
|
||||
qWarning() << "iface requires param:" << ifaceActionParamType.name();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -997,12 +1075,68 @@ void RuleEngine::removeDeviceFromRule(const RuleId &id, const DeviceId &deviceId
|
|||
emit ruleConfigurationChanged(newRule);
|
||||
}
|
||||
|
||||
bool RuleEngine::containsEvent(const Rule &rule, const Event &event)
|
||||
bool RuleEngine::containsEvent(const Rule &rule, const Event &event, const DeviceClassId &deviceClassId)
|
||||
{
|
||||
foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) {
|
||||
if (eventDescriptor == event) {
|
||||
return true;
|
||||
// If this is a device based rule, eventTypeId and deviceId must match
|
||||
if (eventDescriptor.type() == EventDescriptor::TypeDevice) {
|
||||
if (eventDescriptor.eventTypeId() != event.eventTypeId() || eventDescriptor.deviceId() != event.deviceId()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a interface based rule, the device must implement the interface
|
||||
if (eventDescriptor.type() == EventDescriptor::TypeInterface) {
|
||||
DeviceClass dc = GuhCore::instance()->deviceManager()->findDeviceClass(deviceClassId);
|
||||
if (!dc.interfaces().contains(eventDescriptor.interface())) {
|
||||
// DeviceClass for this event doesn't implement the interface for this eventDescriptor
|
||||
continue;
|
||||
}
|
||||
|
||||
EventType et = dc.eventTypes().findById(event.eventTypeId());
|
||||
if (et.name() != eventDescriptor.interfaceEvent()) {
|
||||
// The fired event name does not match with the eventDescriptor's interfaceEvent
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Ok, either device/eventTypeId or interface/interfaceEvent are matching. Compare the paramdescriptor
|
||||
foreach (const ParamDescriptor ¶mDescriptor, eventDescriptor.paramDescriptors()) {
|
||||
switch (paramDescriptor.operatorType()) {
|
||||
case Types::ValueOperatorEquals:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() != paramDescriptor.value()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorNotEquals:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() == paramDescriptor.value()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorGreater:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() <= paramDescriptor.value()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorGreaterOrEqual:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() < paramDescriptor.value()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorLess:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() >= paramDescriptor.value()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorLessOrEqual:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() < paramDescriptor.value()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// All matching!
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include "rule.h"
|
||||
#include "types/event.h"
|
||||
#include "plugin/deviceclass.h"
|
||||
#include "types/deviceclass.h"
|
||||
#include "stateevaluator.h"
|
||||
|
||||
#include <QObject>
|
||||
|
|
@ -59,7 +59,8 @@ public:
|
|||
RuleErrorInvalidCalendarItem,
|
||||
RuleErrorInvalidTimeEventItem,
|
||||
RuleErrorContainsEventBasesAction,
|
||||
RuleErrorNoExitActions
|
||||
RuleErrorNoExitActions,
|
||||
RuleErrorInterfaceNotFound
|
||||
};
|
||||
|
||||
enum RemovePolicy {
|
||||
|
|
@ -99,7 +100,7 @@ signals:
|
|||
void ruleConfigurationChanged(const Rule &rule);
|
||||
|
||||
private:
|
||||
bool containsEvent(const Rule &rule, const Event &event);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -187,6 +187,10 @@ DeviceManager::DeviceManager(HardwareManager *hardwareManager, const QLocale &lo
|
|||
qRegisterMetaType<DeviceClassId>();
|
||||
qRegisterMetaType<DeviceDescriptor>();
|
||||
|
||||
foreach (const Interface &interface, DevicePlugin::allInterfaces()) {
|
||||
m_supportedInterfaces.insert(interface.name(), interface);
|
||||
}
|
||||
|
||||
// Give hardware a chance to start up before loading plugins etc.
|
||||
QMetaObject::invokeMethod(this, "loadPlugins", Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(this, "loadConfiguredDevices", Qt::QueuedConnection);
|
||||
|
|
@ -342,6 +346,18 @@ QList<Vendor> DeviceManager::supportedVendors() const
|
|||
return m_supportedVendors.values();
|
||||
}
|
||||
|
||||
/*! Returns the list of all supported interfaces */
|
||||
Interfaces DeviceManager::supportedInterfaces() const
|
||||
{
|
||||
return m_supportedInterfaces.values();
|
||||
}
|
||||
|
||||
/*! Returns the interface with the given name. If the interface can't be found it will return an invalid interface. */
|
||||
Interface DeviceManager::findInterface(const QString &name)
|
||||
{
|
||||
return m_supportedInterfaces.value(name);
|
||||
}
|
||||
|
||||
/*! Returns all the supported \l{DeviceClass}{DeviceClasses} by all \l{DevicePlugin}{DevicePlugins} loaded in the system.
|
||||
* Optionally filtered by \a vendorId. */
|
||||
QList<DeviceClass> DeviceManager::supportedDevices(const VendorId &vendorId) const
|
||||
|
|
@ -769,6 +785,18 @@ QList<Device *> DeviceManager::findConfiguredDevices(const DeviceClassId &device
|
|||
return ret;
|
||||
}
|
||||
|
||||
QList<Device *> DeviceManager::findConfiguredDevices(const QString &interface) const
|
||||
{
|
||||
QList<Device*> ret;
|
||||
foreach (Device *device, m_configuredDevices) {
|
||||
DeviceClass dc = m_supportedDevices.value(device->deviceClassId());
|
||||
if (dc.interfaces().contains(interface)) {
|
||||
ret.append(device);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Returns all child \l{Device}{Devices} of the given \a device. */
|
||||
QList<Device *> DeviceManager::findChildDevices(const DeviceId &id) const
|
||||
{
|
||||
|
|
@ -793,7 +821,7 @@ DeviceClass DeviceManager::findDeviceClass(const DeviceClassId &deviceClassId) c
|
|||
return DeviceClass();
|
||||
}
|
||||
|
||||
/*! Verify if the given \a params matche the given \a paramTypes. Ith \a requireAll
|
||||
/*! Verify if the given \a params matches the given \a paramTypes. Ith \a requireAll
|
||||
* is true, all \l{ParamList}{Params} has to be valid. Returns \l{DeviceError} to inform about the result.*/
|
||||
DeviceManager::DeviceError DeviceManager::verifyParams(const QList<ParamType> paramTypes, ParamList ¶ms, bool requireAll)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,10 +26,11 @@
|
|||
|
||||
#include "libguh.h"
|
||||
|
||||
#include "plugin/deviceclass.h"
|
||||
#include "plugin/device.h"
|
||||
#include "plugin/devicedescriptor.h"
|
||||
|
||||
#include "types/deviceclass.h"
|
||||
#include "types/interface.h"
|
||||
#include "types/event.h"
|
||||
#include "types/action.h"
|
||||
#include "types/vendor.h"
|
||||
|
|
@ -104,7 +105,10 @@ public:
|
|||
DeviceError setPluginConfig(const PluginId &pluginId, const ParamList &pluginConfig);
|
||||
|
||||
QList<Vendor> supportedVendors() const;
|
||||
Interfaces supportedInterfaces() const;
|
||||
Interface findInterface(const QString &name);
|
||||
QList<DeviceClass> supportedDevices(const VendorId &vendorId = VendorId()) const;
|
||||
|
||||
DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms);
|
||||
|
||||
QList<Device*> configuredDevices() const;
|
||||
|
|
@ -124,6 +128,7 @@ public:
|
|||
|
||||
Device* findConfiguredDevice(const DeviceId &id) const;
|
||||
QList<Device *> findConfiguredDevices(const DeviceClassId &deviceClassId) const;
|
||||
QList<Device *> findConfiguredDevices(const QString &interface) const;
|
||||
QList<Device *> findChildDevices(const DeviceId &id) const;
|
||||
DeviceClass findDeviceClass(const DeviceClassId &deviceClassId) const;
|
||||
|
||||
|
|
@ -181,6 +186,7 @@ private:
|
|||
|
||||
QLocale m_locale;
|
||||
QHash<VendorId, Vendor> m_supportedVendors;
|
||||
QHash<QString, Interface> m_supportedInterfaces;
|
||||
QHash<VendorId, QList<DeviceClassId> > m_vendorDeviceMap;
|
||||
QHash<DeviceClassId, DeviceClass> m_supportedDevices;
|
||||
QHash<DeviceId, Device*> m_configuredDevices;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"states": [
|
||||
{
|
||||
"name": "batteryLevel",
|
||||
"type": "int",
|
||||
"minValue": 0,
|
||||
"maxValue": 100
|
||||
},
|
||||
{
|
||||
"name": "batteryCritical",
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -13,5 +13,6 @@
|
|||
<file>extendedvolumecontroller.json</file>
|
||||
<file>mediametadataprovider.json</file>
|
||||
<file>mediaplayer.json</file>
|
||||
<file>battery.json</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
"states": [
|
||||
{
|
||||
"name": "power",
|
||||
"type": "bool"
|
||||
"type": "bool",
|
||||
"writable": true
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ HEADERS += devicemanager.h \
|
|||
loggingcategories.h \
|
||||
guhsettings.h \
|
||||
plugin/device.h \
|
||||
plugin/deviceclass.h \
|
||||
plugin/deviceplugin.h \
|
||||
plugin/devicedescriptor.h \
|
||||
plugin/devicepairinginfo.h \
|
||||
|
|
@ -53,6 +52,7 @@ HEADERS += devicemanager.h \
|
|||
coap/corelinkparser.h \
|
||||
coap/corelink.h \
|
||||
coap/coapobserveresource.h \
|
||||
types/deviceclass.h \
|
||||
types/action.h \
|
||||
types/actiontype.h \
|
||||
types/state.h \
|
||||
|
|
@ -67,6 +67,7 @@ HEADERS += devicemanager.h \
|
|||
types/ruleaction.h \
|
||||
types/ruleactionparam.h \
|
||||
types/statedescriptor.h \
|
||||
types/interface.h \
|
||||
hardwareresource.h \
|
||||
plugintimer.h \
|
||||
hardwaremanager.h \
|
||||
|
|
@ -75,7 +76,6 @@ SOURCES += devicemanager.cpp \
|
|||
loggingcategories.cpp \
|
||||
guhsettings.cpp \
|
||||
plugin/device.cpp \
|
||||
plugin/deviceclass.cpp \
|
||||
plugin/deviceplugin.cpp \
|
||||
plugin/devicedescriptor.cpp \
|
||||
plugin/devicepairinginfo.cpp \
|
||||
|
|
@ -108,6 +108,7 @@ SOURCES += devicemanager.cpp \
|
|||
coap/corelinkparser.cpp \
|
||||
coap/corelink.cpp \
|
||||
coap/coapobserveresource.cpp \
|
||||
types/deviceclass.cpp \
|
||||
types/action.cpp \
|
||||
types/actiontype.cpp \
|
||||
types/state.cpp \
|
||||
|
|
@ -122,6 +123,7 @@ SOURCES += devicemanager.cpp \
|
|||
types/ruleaction.cpp \
|
||||
types/ruleactionparam.cpp \
|
||||
types/statedescriptor.cpp \
|
||||
types/interface.cpp \
|
||||
hardwareresource.cpp \
|
||||
plugintimer.cpp \
|
||||
hardwaremanager.cpp \
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#include "typeutils.h"
|
||||
#include "libguh.h"
|
||||
|
||||
#include "plugin/deviceclass.h"
|
||||
#include "types/deviceclass.h"
|
||||
#include "types/state.h"
|
||||
#include "types/param.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -797,102 +797,89 @@ void DevicePlugin::loadMetaData()
|
|||
|
||||
QStringList interfaces;
|
||||
foreach (const QJsonValue &value, deviceClassObject.value("interfaces").toArray()) {
|
||||
QVariantMap interfaceMap = loadInterface(value.toString());
|
||||
QVariantList states = interfaceMap.value("states").toList();
|
||||
Interface iface = loadInterface(value.toString());
|
||||
|
||||
StateTypes stateTypes(deviceClass.stateTypes());
|
||||
ActionTypes actionTypes(deviceClass.actionTypes());
|
||||
EventTypes eventTypes(deviceClass.eventTypes());
|
||||
bool valid = true;
|
||||
foreach (const QVariant &stateVariant, states) {
|
||||
StateType stateType = stateTypes.findByName(stateVariant.toMap().value("name").toString());
|
||||
QVariantMap stateMap = stateVariant.toMap();
|
||||
foreach (const StateType &ifaceStateType, iface.stateTypes()) {
|
||||
StateType stateType = stateTypes.findByName(ifaceStateType.name());
|
||||
if (stateType.id().isNull()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement state" << stateMap.value("name").toString();
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement state" << ifaceStateType.name();
|
||||
valid = false;
|
||||
continue;
|
||||
}
|
||||
if (QVariant::nameToType(stateMap.value("type").toByteArray().data()) != stateType.type()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateMap.value("name").toString() << "has not matching type" << stateMap.value("type").toString();
|
||||
if (ifaceStateType.type() != stateType.type()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateType.name() << "has not matching type" << stateType.type() << "!=" << ifaceStateType.type();
|
||||
valid = false;
|
||||
continue;
|
||||
}
|
||||
if (stateMap.contains("minimumValue")) {
|
||||
if (stateMap.value("minimumValue").toString() == "any") {
|
||||
if (ifaceStateType.minValue().isValid() && !ifaceStateType.minValue().isNull()) {
|
||||
if (ifaceStateType.minValue().toString() == "any") {
|
||||
if (stateType.minValue().isNull()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateMap.value("name").toString() << "has no minimum value defined.";
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateType.name() << "has no minimum value defined.";
|
||||
valid = false;
|
||||
continue;
|
||||
}
|
||||
} else if (stateMap.value("minimumValue") != stateType.minValue()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateMap.value("name").toString() << "has not matching minimum value:" << stateMap.value("minimumValue") << "!=" << stateType.minValue();
|
||||
} else if (ifaceStateType.minValue() != stateType.minValue()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateType.name() << "has not matching minimum value:" << ifaceStateType.minValue() << "!=" << stateType.minValue();
|
||||
valid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (stateMap.contains("maximumValue")) {
|
||||
if (stateMap.value("maximumValue").toString() == "any") {
|
||||
if (ifaceStateType.maxValue().isValid() && !ifaceStateType.maxValue().isNull()) {
|
||||
if (ifaceStateType.maxValue().toString() == "any") {
|
||||
if (stateType.maxValue().isNull()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateMap.value("name").toString() << "has no maximum value defined.";
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateType.name() << "has no maximum value defined.";
|
||||
valid = false;
|
||||
continue;
|
||||
}
|
||||
} else if (stateMap.value("maximumValue") != stateType.maxValue()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateMap.value("name").toString() << "has not matching maximum value:" << stateMap.value("maximumValue") << "!=" << stateType.minValue();
|
||||
} else if (ifaceStateType.maxValue() != stateType.maxValue()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateType.name() << "has not matching maximum value:" << ifaceStateType.maxValue() << "!=" << stateType.minValue();
|
||||
valid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (stateMap.contains("allowedValues") && stateMap.value("allowedValues") != stateType.possibleValues()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateMap.value("name").toString() << "has not matching allowed values" << stateMap.value("allowedValues") << "!=" << stateType.possibleValues();
|
||||
valid = false;
|
||||
continue;
|
||||
}
|
||||
if (stateMap.contains("writable") && stateMap.value("writable").toBool() && actionTypes.findById(ActionTypeId(stateType.id().toString())).id().isNull()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateMap.value("name").toString() << "is not writable while it should be";
|
||||
if (!ifaceStateType.possibleValues().isEmpty() && ifaceStateType.possibleValues() != stateType.possibleValues()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but state" << stateType.name() << "has not matching allowed values" << ifaceStateType.possibleValues() << "!=" << stateType.possibleValues();
|
||||
valid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
QVariantList actions = interfaceMap.value("actions").toList();
|
||||
foreach (const QVariant &actionVariant, actions) {
|
||||
QVariantMap actionMap = actionVariant.toMap();
|
||||
ActionType actionType = actionTypes.findByName(actionMap.value("name").toString());
|
||||
foreach (const ActionType &ifaceActionType, iface.actionTypes()) {
|
||||
ActionType actionType = actionTypes.findByName(ifaceActionType.name());
|
||||
if (actionType.id().isNull()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement action" << actionMap.value("name").toString();
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement action" << ifaceActionType.name();
|
||||
valid = false;
|
||||
}
|
||||
QVariantList params = actionMap.value("params").toList();
|
||||
foreach (const QVariant ¶mVariant, params) {
|
||||
ParamType paramType = actionType.paramTypes().findByName(paramVariant.toMap().value("name").toString());
|
||||
foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) {
|
||||
ParamType paramType = actionType.paramTypes().findByName(ifaceActionParamType.name());
|
||||
if (!paramType.isValid()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement action param" << actionMap.value("name").toString() << ":" << paramVariant.toMap().value("name").toString();
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement action param" << ifaceActionType.name() << ":" << ifaceActionParamType.name();
|
||||
valid = false;
|
||||
} else {
|
||||
if (paramType.type() != QVariant::nameToType(paramVariant.toMap().value("type").toString().toLatin1())) {
|
||||
qCWarning(dcDeviceManager()) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but param" << paramType.name() << "is of wrong type:" << QVariant::typeToName(paramType.type()) << "expected:" << paramVariant.toMap().value("type").toString();
|
||||
if (paramType.type() != ifaceActionParamType.type()) {
|
||||
qCWarning(dcDeviceManager()) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but param" << paramType.name() << "is of wrong type:" << QVariant::typeToName(paramType.type()) << "expected:" << QVariant::typeToName(ifaceActionParamType.type());
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
QVariantList events = interfaceMap.value("events").toList();
|
||||
foreach (const QVariant &eventVariant, events) {
|
||||
QVariantMap eventMap = eventVariant.toMap();
|
||||
EventType eventType = eventTypes.findByName(eventMap.value("name").toString());
|
||||
if (eventType.isValid()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement event" << eventMap.value("name").toString();
|
||||
foreach (const EventType &ifaceEventType, iface.eventTypes()) {
|
||||
EventType eventType = eventTypes.findByName(ifaceEventType.name());
|
||||
if (!eventType.isValid()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement event" << ifaceEventType.name();
|
||||
valid = false;
|
||||
}
|
||||
QVariantList params = eventMap.value("params").toList();
|
||||
foreach (const QVariant ¶mVariant, params) {
|
||||
ParamType paramType = eventType.paramTypes().findByName(paramVariant.toMap().value("name").toString());
|
||||
foreach (const ParamType &ifaceEventParamType, ifaceEventType.paramTypes()) {
|
||||
ParamType paramType = eventType.paramTypes().findByName(ifaceEventParamType.name());
|
||||
if (!paramType.isValid()) {
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement action param" << eventMap.value("name").toString() << ":" << paramVariant.toMap().value("name").toString();
|
||||
qCWarning(dcDeviceManager) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but doesn't implement event param" << ifaceEventType.name() << ":" << ifaceEventParamType.name();
|
||||
valid = false;
|
||||
} else {
|
||||
if (paramType.type() != QVariant::nameToType(paramVariant.toMap().value("type").toString().toLatin1())) {
|
||||
qCWarning(dcDeviceManager()) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but param" << paramType.name() << "is of wrong type:" << QVariant::typeToName(paramType.type()) << "expected:" << paramVariant.toMap().value("type").toString();
|
||||
if (paramType.type() != ifaceEventParamType.type()) {
|
||||
qCWarning(dcDeviceManager()) << "DeviceClass" << deviceClass.name() << "claims to implement interface" << value.toString() << "but param" << paramType.name() << "is of wrong type:" << QVariant::typeToName(paramType.type()) << "expected:" << QVariant::typeToName(ifaceEventParamType.type());
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1038,36 +1025,100 @@ QPair<bool, DeviceClass::DeviceIcon> DevicePlugin::loadAndVerifyDeviceIcon(const
|
|||
return QPair<bool, DeviceClass::DeviceIcon>(true, (DeviceClass::DeviceIcon)enumValue);
|
||||
}
|
||||
|
||||
QVariantMap DevicePlugin::loadInterface(const QString &name)
|
||||
Interfaces DevicePlugin::allInterfaces()
|
||||
{
|
||||
Interfaces ret;
|
||||
QDir dir(":/interfaces/");
|
||||
foreach (const QFileInfo &ifaceFile, dir.entryInfoList()) {
|
||||
ret.append(loadInterface(ifaceFile.baseName()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Interface DevicePlugin::loadInterface(const QString &name)
|
||||
{
|
||||
Interface iface;
|
||||
QFile f(QString(":/interfaces/%1.json").arg(name));
|
||||
if (!f.open(QFile::ReadOnly)) {
|
||||
qCWarning(dcDeviceManager()) << "Failed to load interface" << name;
|
||||
return QVariantMap();
|
||||
return iface;
|
||||
}
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(f.readAll(), &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qCWarning(dcDeviceManager) << "Cannot load interface definition for interface" << name << ":" << error.errorString();
|
||||
return QVariantMap();
|
||||
return iface;
|
||||
}
|
||||
QVariantMap content = jsonDoc.toVariant().toMap();
|
||||
if (content.contains("extends")) {
|
||||
QVariantMap parentContent = loadInterface(content.value("extends").toString());
|
||||
|
||||
QVariantList statesList = content.value("states").toList();
|
||||
statesList.append(parentContent.value("states").toList());
|
||||
content["states"] = statesList;
|
||||
|
||||
QVariantList actionsList = content.value("actions").toList();
|
||||
actionsList.append(parentContent.value("actions").toList());
|
||||
content["actions"] = actionsList;
|
||||
|
||||
QVariantList eventsList = content.value("events").toList();
|
||||
eventsList.append(parentContent.value("events").toList());
|
||||
content["events"] = eventsList;
|
||||
iface = loadInterface(content.value("extends").toString());
|
||||
}
|
||||
return content;
|
||||
|
||||
StateTypes stateTypes;
|
||||
ActionTypes actionTypes;
|
||||
EventTypes eventTypes;
|
||||
foreach (const QVariant &stateVariant, content.value("states").toList()) {
|
||||
StateType stateType(StateTypeId::fromUuid(QUuid()));
|
||||
stateType.setName(stateVariant.toMap().value("name").toString());
|
||||
stateType.setType(QVariant::nameToType(stateVariant.toMap().value("type").toByteArray()));
|
||||
stateType.setPossibleValues(stateVariant.toMap().value("allowedValues").toList());
|
||||
stateType.setMinValue(stateVariant.toMap().value("minValue"));
|
||||
stateType.setMaxValue(stateVariant.toMap().value("maxValue"));
|
||||
stateTypes.append(stateType);
|
||||
|
||||
EventType stateChangeEventType(EventTypeId::fromUuid(QUuid()));
|
||||
stateChangeEventType.setName(stateType.name());
|
||||
ParamType stateChangeEventParamType;
|
||||
stateChangeEventParamType.setName(stateType.name());
|
||||
stateChangeEventParamType.setType(stateType.type());
|
||||
stateChangeEventParamType.setAllowedValues(stateType.possibleValues());
|
||||
stateChangeEventParamType.setMinValue(stateType.minValue());
|
||||
stateChangeEventParamType.setMaxValue(stateType.maxValue());
|
||||
stateChangeEventType.setParamTypes(ParamTypes() << stateChangeEventParamType);
|
||||
eventTypes.append(stateChangeEventType);
|
||||
|
||||
if (stateVariant.toMap().value("writable", false).toBool()) {
|
||||
ActionType stateChangeActionType(ActionTypeId::fromUuid(QUuid()));
|
||||
stateChangeActionType.setName(stateType.name());
|
||||
stateChangeActionType.setParamTypes(ParamTypes() << stateChangeEventParamType);
|
||||
actionTypes.append(stateChangeActionType);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const QVariant &actionVariant, content.value("actions").toList()) {
|
||||
ActionType actionType(ActionTypeId::fromUuid(QUuid()));
|
||||
actionType.setName(actionVariant.toMap().value("name").toString());
|
||||
ParamTypes paramTypes;
|
||||
foreach (const QVariant &actionParamVariant, actionVariant.toMap().value("params").toList()) {
|
||||
ParamType paramType;
|
||||
paramType.setName(actionParamVariant.toMap().value("name").toString());
|
||||
paramType.setType(QVariant::nameToType(actionParamVariant.toMap().value("type").toByteArray()));
|
||||
paramType.setAllowedValues(actionParamVariant.toMap().value("allowedValues").toList());
|
||||
paramType.setMinValue(actionParamVariant.toMap().value("min"));
|
||||
paramTypes.append(paramType);
|
||||
}
|
||||
actionType.setParamTypes(paramTypes);
|
||||
actionTypes.append(actionType);
|
||||
}
|
||||
|
||||
foreach (const QVariant &eventVariant, content.value("events").toList()) {
|
||||
EventType eventType(EventTypeId::fromUuid(QUuid()));
|
||||
eventType.setName(eventVariant.toMap().value("name").toString());
|
||||
ParamTypes paramTypes;
|
||||
foreach (const QVariant &eventParamVariant, eventVariant.toMap().value("params").toList()) {
|
||||
ParamType paramType;
|
||||
paramType.setName(eventParamVariant.toMap().value("name").toString());
|
||||
paramType.setType(QVariant::nameToType(eventParamVariant.toMap().value("type").toByteArray()));
|
||||
paramType.setAllowedValues(eventParamVariant.toMap().value("allowedValues").toList());
|
||||
paramType.setMinValue(eventParamVariant.toMap().value("minValue"));
|
||||
paramType.setMaxValue(eventParamVariant.toMap().value("maxValue"));
|
||||
paramTypes.append(paramType);
|
||||
}
|
||||
eventType.setParamTypes(paramTypes);
|
||||
eventTypes.append(eventType);
|
||||
}
|
||||
|
||||
return Interface(name, iface.actionTypes() << actionTypes, iface.eventTypes() << eventTypes, iface.stateTypes() << stateTypes);
|
||||
}
|
||||
|
||||
QStringList DevicePlugin::generateInterfaceParentList(const QString &interface)
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@
|
|||
#define DEVICEPLUGIN_H
|
||||
|
||||
#include "devicemanager.h"
|
||||
#include "deviceclass.h"
|
||||
|
||||
#include "libguh.h"
|
||||
#include "typeutils.h"
|
||||
|
||||
#include "types/deviceclass.h"
|
||||
#include "types/event.h"
|
||||
#include "types/action.h"
|
||||
#include "types/vendor.h"
|
||||
|
|
@ -119,7 +119,11 @@ private:
|
|||
QPair<bool, DeviceClass::BasicTag> loadAndVerifyBasicTag(const QString &basicTag) const;
|
||||
QPair<bool, DeviceClass::DeviceIcon> loadAndVerifyDeviceIcon(const QString &deviceIcon) const;
|
||||
|
||||
static QVariantMap loadInterface(const QString &name);
|
||||
// FIXME: This is expensive because it will open all the files.
|
||||
// Once DeviceManager is in libguh-core this should probably be there too.
|
||||
// I didn't want to add even more dependencies on the devicemanager into here, so reading the list here for now.
|
||||
static Interfaces allInterfaces();
|
||||
static Interface loadInterface(const QString &name);
|
||||
static QStringList generateInterfaceParentList(const QString &interface);
|
||||
|
||||
QTranslator *m_translator = nullptr;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ private:
|
|||
class ActionTypes: public QList<ActionType>
|
||||
{
|
||||
public:
|
||||
ActionTypes() = default;
|
||||
ActionTypes(const QList<ActionType> &other);
|
||||
ActionType findByName(const QString &name);
|
||||
ActionType findById(const ActionTypeId &id);
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ bool DeviceClass::hasStateType(const StateTypeId &stateTypeId)
|
|||
|
||||
/*! Returns the eventTypes of this DeviceClass. \{Device}{Devices} created
|
||||
from this \l{DeviceClass} must have their events matching to this template. */
|
||||
QList<EventType> DeviceClass::eventTypes() const
|
||||
EventTypes DeviceClass::eventTypes() const
|
||||
{
|
||||
return m_eventTypes;
|
||||
}
|
||||
|
|
@ -361,7 +361,7 @@ bool DeviceClass::hasEventType(const EventTypeId &eventTypeId)
|
|||
|
||||
/*! Returns the actionTypes of this DeviceClass. \{Device}{Devices} created
|
||||
from this \l{DeviceClass} must have their actions matching to this template. */
|
||||
QList<ActionType> DeviceClass::actionTypes() const
|
||||
ActionTypes DeviceClass::actionTypes() const
|
||||
{
|
||||
return m_actionTypes;
|
||||
}
|
||||
|
|
@ -152,11 +152,11 @@ public:
|
|||
void setStateTypes(const QList<StateType> &stateTypes);
|
||||
bool hasStateType(const StateTypeId &stateTypeId);
|
||||
|
||||
QList<EventType> eventTypes() const;
|
||||
EventTypes eventTypes() const;
|
||||
void setEventTypes(const QList<EventType> &eventTypes);
|
||||
bool hasEventType(const EventTypeId &eventTypeId);
|
||||
|
||||
QList<ActionType> actionTypes() const;
|
||||
ActionTypes actionTypes() const;
|
||||
void setActionTypes(const QList<ActionType> &actionTypes);
|
||||
bool hasActionType(const ActionTypeId &actionTypeId);
|
||||
|
||||
|
|
@ -31,6 +31,11 @@
|
|||
|
||||
An EventDescriptor describes an \l{Event} in order to match it with a \l{guhserver::Rule}.
|
||||
|
||||
An EventDescriptor can either be bound to a certain device/eventtype, or to an interface.
|
||||
If an event is bound to a device, it will only match when the given device fires the given event.
|
||||
If an event is bound to an interface, it will match the given event for all the devices implementing
|
||||
the given interface.
|
||||
|
||||
\sa Event, EventType, guhserver::Rule
|
||||
*/
|
||||
|
||||
|
|
@ -44,6 +49,25 @@ EventDescriptor::EventDescriptor(const EventTypeId &eventTypeId, const DeviceId
|
|||
{
|
||||
}
|
||||
|
||||
EventDescriptor::EventDescriptor(const QString &interface, const QString &interfaceEvent, const QList<ParamDescriptor> ¶mDescriptors):
|
||||
m_interface(interface),
|
||||
m_interfaceEvent(interfaceEvent),
|
||||
m_paramDescriptors(paramDescriptors)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
EventDescriptor::Type EventDescriptor::type() const
|
||||
{
|
||||
return (!m_deviceId.isNull() && !m_eventTypeId.isNull()) ? TypeDevice : TypeInterface;
|
||||
}
|
||||
|
||||
/*! Returns true if the EventDescriptor is valid, that is, when it has either enough data to describe a device/eventType or an interface/interfaceEvent pair. */
|
||||
bool EventDescriptor::isValid() const
|
||||
{
|
||||
return (!m_deviceId.isNull() && !m_eventTypeId.isNull()) || (!m_interface.isEmpty() && !m_interfaceEvent.isEmpty());
|
||||
}
|
||||
|
||||
/*! Returns the id of the \l{EventType} which describes this Event. */
|
||||
EventTypeId EventDescriptor::eventTypeId() const
|
||||
{
|
||||
|
|
@ -56,6 +80,18 @@ DeviceId EventDescriptor::deviceId() const
|
|||
return m_deviceId;
|
||||
}
|
||||
|
||||
/*! Returns the interface associated with this EventDescriptor. */
|
||||
QString EventDescriptor::interface() const
|
||||
{
|
||||
return m_interface;
|
||||
}
|
||||
|
||||
/*! Returns the interface's event name associated with this EventDescriptor.*/
|
||||
QString EventDescriptor::interfaceEvent() const
|
||||
{
|
||||
return m_interfaceEvent;
|
||||
}
|
||||
|
||||
/*! Returns the parameters of this Event. */
|
||||
QList<ParamDescriptor> EventDescriptor::paramDescriptors() const
|
||||
{
|
||||
|
|
@ -97,51 +133,6 @@ bool EventDescriptor::operator ==(const EventDescriptor &other) const
|
|||
&& paramsMatch;
|
||||
}
|
||||
|
||||
/*! Compare this EventDescriptor to the Event given by \a event.
|
||||
* Events are equal (returns true) if eventTypeId, deviceId and params match. */
|
||||
bool EventDescriptor::operator ==(const Event &event) const
|
||||
{
|
||||
if (m_eventTypeId != event.eventTypeId() || m_deviceId != event.deviceId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (const ParamDescriptor ¶mDescriptor, m_paramDescriptors) {
|
||||
switch (paramDescriptor.operatorType()) {
|
||||
case Types::ValueOperatorEquals:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() != paramDescriptor.value()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorNotEquals:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() == paramDescriptor.value()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorGreater:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() <= paramDescriptor.value()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorGreaterOrEqual:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() < paramDescriptor.value()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorLess:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() >= paramDescriptor.value()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Types::ValueOperatorLessOrEqual:
|
||||
if (event.param(paramDescriptor.paramTypeId()).value() < paramDescriptor.value()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Writes the eventTypeId and the deviceId of the given \a eventDescriptor to \a dbg. */
|
||||
QDebug operator<<(QDebug dbg, const EventDescriptor &eventDescriptor)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,22 +36,34 @@
|
|||
class LIBGUH_EXPORT EventDescriptor
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
TypeDevice,
|
||||
TypeInterface
|
||||
};
|
||||
|
||||
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>());
|
||||
|
||||
Type type() const;
|
||||
bool isValid() const;
|
||||
|
||||
EventTypeId eventTypeId() const;
|
||||
DeviceId deviceId() const;
|
||||
|
||||
QString interface() const;
|
||||
QString interfaceEvent() const;
|
||||
|
||||
QList<ParamDescriptor> paramDescriptors() const;
|
||||
void setParamDescriptors(const QList<ParamDescriptor> ¶mDescriptors);
|
||||
ParamDescriptor paramDescriptor(const ParamTypeId ¶mTypeId) const;
|
||||
|
||||
bool operator ==(const EventDescriptor &other) const;
|
||||
|
||||
bool operator ==(const Event &event) const;
|
||||
|
||||
private:
|
||||
EventTypeId m_eventTypeId;
|
||||
DeviceId m_deviceId;
|
||||
QString m_interface;
|
||||
QString m_interfaceEvent;
|
||||
QList<ParamDescriptor> m_paramDescriptors;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ private:
|
|||
class EventTypes: public QList<EventType>
|
||||
{
|
||||
public:
|
||||
EventTypes() = default;
|
||||
EventTypes(const QList<EventType> &other);
|
||||
EventType findByName(const QString &name);
|
||||
EventType findById(const EventTypeId &id);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2017 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "interface.h"
|
||||
|
||||
Interface::Interface(const QString &name, const ActionTypes &actionTypes, const EventTypes &eventTypes, const StateTypes &stateTypes):
|
||||
m_name(name),
|
||||
m_actionTypes(actionTypes),
|
||||
m_eventTypes(eventTypes),
|
||||
m_stateTypes(stateTypes)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString Interface::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
ActionTypes Interface::actionTypes() const
|
||||
{
|
||||
return m_actionTypes;
|
||||
}
|
||||
|
||||
EventTypes Interface::eventTypes() const
|
||||
{
|
||||
return m_eventTypes;
|
||||
}
|
||||
|
||||
StateTypes Interface::stateTypes() const
|
||||
{
|
||||
return m_stateTypes;
|
||||
}
|
||||
|
||||
bool Interface::isValid() const
|
||||
{
|
||||
return !m_name.isEmpty();
|
||||
}
|
||||
|
||||
Interfaces::Interfaces(const QList<Interface> &other)
|
||||
{
|
||||
foreach (const Interface &iface, other) {
|
||||
append(iface);
|
||||
}
|
||||
}
|
||||
|
||||
Interface Interfaces::findByName(const QString &name)
|
||||
{
|
||||
foreach (const Interface &interface, *this) {
|
||||
if (interface.name() == name) {
|
||||
return interface;
|
||||
}
|
||||
}
|
||||
return Interface();
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2017 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef INTERFACE_H
|
||||
#define INTERFACE_H
|
||||
|
||||
#include "eventtype.h"
|
||||
#include "actiontype.h"
|
||||
#include "statetype.h"
|
||||
|
||||
class Interface{
|
||||
public:
|
||||
Interface() = default;
|
||||
Interface(const QString &name, const ActionTypes &actionTypes, const EventTypes &eventTypes, const StateTypes &stateTypes);
|
||||
|
||||
QString name() const;
|
||||
|
||||
ActionTypes actionTypes() const;
|
||||
EventTypes eventTypes() const;
|
||||
StateTypes stateTypes() const;
|
||||
|
||||
bool isValid() const;
|
||||
private:
|
||||
QUuid m_id;
|
||||
QString m_name;
|
||||
ActionTypes m_actionTypes;
|
||||
EventTypes m_eventTypes;
|
||||
StateTypes m_stateTypes;
|
||||
};
|
||||
|
||||
class Interfaces: public QList<Interface>
|
||||
{
|
||||
public:
|
||||
Interfaces() = default;
|
||||
Interfaces(const QList<Interface> &other);
|
||||
Interface findByName(const QString &name);
|
||||
};
|
||||
|
||||
#endif // INTERFACE_H
|
||||
|
|
@ -38,18 +38,31 @@
|
|||
#include "ruleaction.h"
|
||||
|
||||
/*! Constructs a RuleAction with the given by \a actionTypeId and \a deviceId. */
|
||||
RuleAction::RuleAction(const ActionTypeId &actionTypeId, const DeviceId &deviceId) :
|
||||
RuleAction::RuleAction(const ActionTypeId &actionTypeId, const DeviceId &deviceId, const RuleActionParamList ¶ms):
|
||||
m_id(ActionId::createActionId()),
|
||||
m_actionTypeId(actionTypeId),
|
||||
m_deviceId(deviceId)
|
||||
m_deviceId(deviceId),
|
||||
m_ruleActionParams(params)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Constructs a RuleAction with the given by \a interface and \a interfaceAction. */
|
||||
RuleAction::RuleAction(const QString &interface, const QString &interfaceAction, const RuleActionParamList ¶ms) :
|
||||
m_interface(interface),
|
||||
m_interfaceAction(interfaceAction),
|
||||
m_ruleActionParams(params)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Constructs a copy of the given \a other RuleAction. */
|
||||
RuleAction::RuleAction(const RuleAction &other) :
|
||||
m_id(other.id()),
|
||||
m_actionTypeId(other.actionTypeId()),
|
||||
m_deviceId(other.deviceId()),
|
||||
m_interface(other.interface()),
|
||||
m_interfaceAction(other.interfaceAction()),
|
||||
m_ruleActionParams(other.ruleActionParams())
|
||||
{
|
||||
|
||||
|
|
@ -64,7 +77,13 @@ ActionId RuleAction::id() const
|
|||
/*! Return true, if the actionTypeId and the deviceId of this RuleAction are valid (set).*/
|
||||
bool RuleAction::isValid() const
|
||||
{
|
||||
return !m_actionTypeId.isNull() && !m_deviceId.isNull();
|
||||
return (!m_actionTypeId.isNull() && !m_deviceId.isNull()) || (!m_interface.isEmpty() && !m_interfaceAction.isEmpty());
|
||||
}
|
||||
|
||||
/*! Returns whether this RuleAction is targetting a specific device or rather an interface. */
|
||||
RuleAction::Type RuleAction::type() const
|
||||
{
|
||||
return (!m_actionTypeId.isNull() && !m_deviceId.isNull()) ? TypeDevice : TypeInterface;
|
||||
}
|
||||
|
||||
/*! Return true, if this RuleAction contains a \l{RuleActionParam} which is based on an EventTypeId.*/
|
||||
|
|
@ -103,6 +122,18 @@ DeviceId RuleAction::deviceId() const
|
|||
return m_deviceId;
|
||||
}
|
||||
|
||||
/*! Returns the name of the interface associated with this RuleAction. */
|
||||
QString RuleAction::interface() const
|
||||
{
|
||||
return m_interface;
|
||||
}
|
||||
|
||||
/*! Returns the name of the action of the associated interface. */
|
||||
QString RuleAction::interfaceAction() const
|
||||
{
|
||||
return m_interfaceAction;
|
||||
}
|
||||
|
||||
/*! Returns the \l{RuleActionParamList} of this RuleAction.
|
||||
* \sa RuleActionParam, */
|
||||
RuleActionParamList RuleAction::ruleActionParams() const
|
||||
|
|
@ -118,7 +149,7 @@ void RuleAction::setRuleActionParams(const RuleActionParamList &ruleActionParams
|
|||
}
|
||||
|
||||
/*! Returns the \l{RuleActionParam} of this RuleAction with the given \a ruleActionParamTypeId.
|
||||
* If there is no \l{RuleActionParam} with th given name an invalid \l{RuleActionParam} will be returnend.
|
||||
* If there is no \l{RuleActionParam} with th given id an invalid \l{RuleActionParam} will be returnend.
|
||||
* \sa RuleActionParam, */
|
||||
RuleActionParam RuleAction::ruleActionParam(const ParamTypeId &ruleActionParamTypeId) const
|
||||
{
|
||||
|
|
@ -130,6 +161,19 @@ RuleActionParam RuleAction::ruleActionParam(const ParamTypeId &ruleActionParamTy
|
|||
return RuleActionParam(QString());
|
||||
}
|
||||
|
||||
/*! Returns the \l{RuleActionParam} of this RuleAction with the given \a ruleActionParamName.
|
||||
* If there is no \l{RuleActionParam} with th given name an invalid \l{RuleActionParam} will be returnend.
|
||||
* \sa RuleActionParam, */
|
||||
RuleActionParam RuleAction::ruleActionParam(const QString &ruleActionParamName) const
|
||||
{
|
||||
foreach (const RuleActionParam &ruleActionParam, m_ruleActionParams) {
|
||||
if (ruleActionParam.paramName() == ruleActionParamName) {
|
||||
return ruleActionParam;
|
||||
}
|
||||
}
|
||||
return RuleActionParam(QString());
|
||||
}
|
||||
|
||||
/*! Copy the data to a \l{RuleAction} from an \a other rule action. */
|
||||
void RuleAction::operator=(const RuleAction &other)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,12 +31,19 @@
|
|||
class LIBGUH_EXPORT RuleAction
|
||||
{
|
||||
public:
|
||||
explicit RuleAction(const ActionTypeId &actionTypeId = ActionTypeId(), const DeviceId &deviceId = DeviceId());
|
||||
enum Type {
|
||||
TypeDevice,
|
||||
TypeInterface
|
||||
};
|
||||
explicit RuleAction(const ActionTypeId &actionTypeId = ActionTypeId(), const DeviceId &deviceId = DeviceId(), const RuleActionParamList ¶ms = RuleActionParamList());
|
||||
explicit RuleAction(const QString &interface, const QString &interfaceAction, const RuleActionParamList ¶ms = RuleActionParamList());
|
||||
RuleAction(const RuleAction &other);
|
||||
|
||||
ActionId id() const;
|
||||
bool isValid() const;
|
||||
|
||||
Type type() const;
|
||||
|
||||
bool isEventBased() const;
|
||||
|
||||
Action toAction() const;
|
||||
|
|
@ -44,9 +51,13 @@ public:
|
|||
ActionTypeId actionTypeId() const;
|
||||
DeviceId deviceId() const;
|
||||
|
||||
QString interface() const;
|
||||
QString interfaceAction() const;
|
||||
|
||||
RuleActionParamList ruleActionParams() const;
|
||||
void setRuleActionParams(const RuleActionParamList &ruleActionParams);
|
||||
RuleActionParam ruleActionParam(const ParamTypeId &ruleActionParamTypeId) const;
|
||||
RuleActionParam ruleActionParam(const QString &ruleActionParamName) const;
|
||||
|
||||
void operator=(const RuleAction &other);
|
||||
|
||||
|
|
@ -54,6 +65,8 @@ private:
|
|||
ActionId m_id;
|
||||
ActionTypeId m_actionTypeId;
|
||||
DeviceId m_deviceId;
|
||||
QString m_interface;
|
||||
QString m_interfaceAction;
|
||||
RuleActionParamList m_ruleActionParams;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -57,12 +57,28 @@ RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant
|
|||
{
|
||||
}
|
||||
|
||||
/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a value, \a eventTypeId and \a eventParamTypeId.
|
||||
* \sa Param, Event, */
|
||||
RuleActionParam::RuleActionParam(const QString ¶mName, const QVariant &value, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId):
|
||||
m_paramName(paramName),
|
||||
m_value(value),
|
||||
m_eventTypeId(eventTypeId),
|
||||
m_eventParamTypeId(eventParamTypeId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*! Returns the \l ParamTypeId of this \l RuleActionParam. */
|
||||
ParamTypeId RuleActionParam::paramTypeId() const
|
||||
{
|
||||
return m_paramTypeId;
|
||||
}
|
||||
|
||||
QString RuleActionParam::paramName() const
|
||||
{
|
||||
return m_paramName;
|
||||
}
|
||||
|
||||
/*! Returns the eventParamTypeId of this RuleActionParam. */
|
||||
ParamTypeId RuleActionParam::eventParamTypeId() const
|
||||
{
|
||||
|
|
@ -136,6 +152,17 @@ bool RuleActionParamList::hasParam(const ParamTypeId &ruleActionParamTypeId) con
|
|||
return m_ids.contains(ruleActionParamTypeId);
|
||||
}
|
||||
|
||||
/*! Returns true if this \l{RuleActionParamList} contains a \l{RuleActionParam} with the given \a ruleActionParamName. */
|
||||
bool RuleActionParamList::hasParam(const QString &ruleActionParamName) const
|
||||
{
|
||||
foreach (const RuleActionParam ¶m, *this) {
|
||||
if (param.paramName() == ruleActionParamName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Returns the value of the \l{RuleActionParam} with the given \a ruleActionParamTypeId. */
|
||||
QVariant RuleActionParamList::paramValue(const ParamTypeId &ruleActionParamTypeId) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,9 +36,11 @@ class LIBGUH_EXPORT RuleActionParam
|
|||
{
|
||||
public:
|
||||
RuleActionParam(const Param ¶m = Param());
|
||||
RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant(), const EventTypeId &eventTypeId = EventTypeId(), const ParamTypeId &eventParamName = ParamTypeId());
|
||||
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());
|
||||
|
||||
ParamTypeId paramTypeId() const;
|
||||
QString paramName() const;
|
||||
|
||||
ParamTypeId eventParamTypeId() const;
|
||||
void setEventParamTypeId(const ParamTypeId &eventParamTypeId);
|
||||
|
|
@ -53,6 +55,7 @@ public:
|
|||
|
||||
private:
|
||||
ParamTypeId m_paramTypeId;
|
||||
QString m_paramName;
|
||||
QVariant m_value;
|
||||
EventTypeId m_eventTypeId;
|
||||
ParamTypeId m_eventParamTypeId;
|
||||
|
|
@ -65,6 +68,7 @@ class LIBGUH_EXPORT RuleActionParamList: public QList<RuleActionParam>
|
|||
{
|
||||
public:
|
||||
bool hasParam(const ParamTypeId &ruleActionParamTypeId) const;
|
||||
bool hasParam(const QString &ruleActionParamName) const;
|
||||
QVariant paramValue(const ParamTypeId &ruleActionParamName) const;
|
||||
bool setParamValue(const ParamTypeId &ruleActionParamTypeId, const QVariant &value);
|
||||
RuleActionParamList operator<<(const RuleActionParam &ruleActionParam);
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ private:
|
|||
class StateTypes: public QList<StateType>
|
||||
{
|
||||
public:
|
||||
StateTypes() = default;
|
||||
StateTypes(const QList<StateType> &other);
|
||||
StateType findByName(const QString &name);
|
||||
StateType findById(const StateTypeId &id);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
"name": "mock",
|
||||
"displayName": "Mock Device",
|
||||
"deviceIcon": "Tune",
|
||||
"interfaces": ["gateway", "light", "mediacontroller"],
|
||||
"interfaces": ["gateway", "light", "mediacontroller", "battery"],
|
||||
"basicTags": [
|
||||
"Device",
|
||||
"Actuator",
|
||||
|
|
@ -91,7 +91,36 @@
|
|||
"defaultValue": false,
|
||||
"type": "bool",
|
||||
"cached": false
|
||||
},
|
||||
{
|
||||
"id": "6c8ab9a6-0164-4795-b829-f4394fe4edc4",
|
||||
"name": "batteryLevel",
|
||||
"displayName": "battery level",
|
||||
"displayNameEvent": "battery level",
|
||||
"type": "int",
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "580bc611-1a55-41f3-996f-8d3ccf543db3",
|
||||
"name": "batteryCritical",
|
||||
"displayName": "battery level critical",
|
||||
"displayNameEvent": "battery level critical",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "064aed0d-da4c-49d4-b236-60f97e98ff84",
|
||||
"name": "power",
|
||||
"displayName": "powered",
|
||||
"displayNameEvent": "powered changed",
|
||||
"displayNameAction": "set power",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"writable": true
|
||||
}
|
||||
|
||||
],
|
||||
"eventTypes": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
#include "httpdaemon.h"
|
||||
|
||||
#include "plugin/device.h"
|
||||
#include "plugin/deviceclass.h"
|
||||
#include "plugin/deviceplugin.h"
|
||||
#include "types/deviceclass.h"
|
||||
#include "types/statetype.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
|
|
@ -137,7 +137,13 @@ QString HttpDaemon::generateHeader()
|
|||
|
||||
QString HttpDaemon::generateWebPage()
|
||||
{
|
||||
DeviceClass deviceClass = m_plugin->supportedDevices().first();
|
||||
DeviceClass deviceClass;
|
||||
foreach (const DeviceClass &dc, m_plugin->supportedDevices()) {
|
||||
if (dc.id() == m_device->deviceClassId()) {
|
||||
deviceClass = dc;
|
||||
}
|
||||
}
|
||||
Q_ASSERT(deviceClass.isValid());
|
||||
|
||||
QString body = QString(
|
||||
"<html>"
|
||||
|
|
@ -156,7 +162,7 @@ QString HttpDaemon::generateWebPage()
|
|||
for (int i = 0; i < deviceClass.stateTypes().count(); ++i) {
|
||||
body.append("<tr>");
|
||||
body.append("<form action=\"/setstate\" method=\"get\">");
|
||||
const StateType &stateType = deviceClass.stateTypes().at(i);
|
||||
StateType stateType = deviceClass.stateTypes().at(i);
|
||||
body.append("<td>" + stateType.name() + "</td>");
|
||||
body.append(QString("<td><input type='input'' name='%1' value='%2'></td>").arg(stateType.id().toString()).arg(m_device->states().at(i).value().toString()));
|
||||
body.append("<td><input type=submit value='Set State'/></td>");
|
||||
|
|
@ -170,14 +176,14 @@ QString HttpDaemon::generateWebPage()
|
|||
|
||||
body.append("<table>");
|
||||
for (int i = 0; i < deviceClass.eventTypes().count(); ++i) {
|
||||
const EventType &eventType = deviceClass.eventTypes().at(i);
|
||||
EventType eventType = deviceClass.eventTypes().at(i);
|
||||
body.append(QString(
|
||||
"<tr>"
|
||||
"<form action=\"/generateevent\" method=\"get\">"
|
||||
"<td>%1<input type='hidden' name='eventtypeid' value='%2'/></td>"
|
||||
"<td>").arg(eventType.name()).arg(eventType.id().toString()));
|
||||
if (!eventType.name().endsWith(" changed")) {
|
||||
body.append("<input type='submit' value='Generate'/>");
|
||||
if (!eventType.displayName().endsWith(" changed")) {
|
||||
body.append(QStringLiteral("<input type='submit' value='Generate'/>"));
|
||||
}
|
||||
body.append("</td>"
|
||||
"</form>"
|
||||
|
|
@ -211,7 +217,6 @@ QString HttpDaemon::generateWebPage()
|
|||
}
|
||||
body.append("</table>");
|
||||
|
||||
|
||||
body.append("</body></html>\n");
|
||||
|
||||
return generateHeader() + body;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
1.0
|
||||
1.1
|
||||
{
|
||||
"methods": {
|
||||
"Actions.ExecuteAction": {
|
||||
|
|
@ -1152,8 +1152,10 @@
|
|||
]
|
||||
},
|
||||
"EventDescriptor": {
|
||||
"deviceId": "Uuid",
|
||||
"eventTypeId": "Uuid",
|
||||
"o:deviceId": "Uuid",
|
||||
"o:eventTypeId": "Uuid",
|
||||
"o:interface": "String",
|
||||
"o:interfaceEvent": "String",
|
||||
"o:paramDescriptors": [
|
||||
"$ref:ParamDescriptor"
|
||||
]
|
||||
|
|
@ -1325,8 +1327,10 @@
|
|||
"timeDescriptor": "$ref:TimeDescriptor"
|
||||
},
|
||||
"RuleAction": {
|
||||
"actionTypeId": "Uuid",
|
||||
"deviceId": "Uuid",
|
||||
"o:actionTypeId": "Uuid",
|
||||
"o:deviceId": "Uuid",
|
||||
"o:interface": "String",
|
||||
"o:interfaceAction": "String",
|
||||
"o:ruleActionParams": [
|
||||
"$ref:RuleActionParam"
|
||||
]
|
||||
|
|
@ -1334,8 +1338,9 @@
|
|||
"RuleActionParam": {
|
||||
"o:eventParamTypeId": "Uuid",
|
||||
"o:eventTypeId": "Uuid",
|
||||
"o:value": "$ref:BasicType",
|
||||
"paramTypeId": "Uuid"
|
||||
"o:paramName": "String",
|
||||
"o:paramTypeId": "Uuid",
|
||||
"o:value": "$ref:BasicType"
|
||||
},
|
||||
"RuleDescription": {
|
||||
"active": "Bool",
|
||||
|
|
@ -1364,7 +1369,8 @@
|
|||
"RuleErrorInvalidCalendarItem",
|
||||
"RuleErrorInvalidTimeEventItem",
|
||||
"RuleErrorContainsEventBasesAction",
|
||||
"RuleErrorNoExitActions"
|
||||
"RuleErrorNoExitActions",
|
||||
"RuleErrorInterfaceNotFound"
|
||||
],
|
||||
"ServerConfiguration": {
|
||||
"address": "String",
|
||||
|
|
|
|||
|
|
@ -241,9 +241,13 @@ void TestDevices::verifyInterfaces()
|
|||
QVERIFY(!mockDevice.isEmpty());
|
||||
|
||||
QVariantList interfaces = mockDevice.value("interfaces").toList();
|
||||
// Must contain gateway, but must not contain anything else as device manager should filter it away
|
||||
QCOMPARE(interfaces.count() == 1, true);
|
||||
// Must contain gateway, light and battery, but must not contain mediacontroller as the device manager should filter
|
||||
// that away because it doesn't implement all the required states.
|
||||
QCOMPARE(interfaces.count(), 3);
|
||||
QVERIFY(interfaces.contains("gateway"));
|
||||
QVERIFY(interfaces.contains("battery"));
|
||||
QVERIFY(interfaces.contains("light"));
|
||||
QVERIFY(!interfaces.contains("mediacontroller"));
|
||||
}
|
||||
|
||||
void TestDevices::addConfiguredDevice_data()
|
||||
|
|
@ -631,25 +635,33 @@ void TestDevices::parentChildDevices()
|
|||
void TestDevices::getActionTypes_data()
|
||||
{
|
||||
QTest::addColumn<DeviceClassId>("deviceClassId");
|
||||
QTest::addColumn<int>("resultCount");
|
||||
QTest::addColumn<QList<ActionTypeId> >("actionTypeTestData");
|
||||
|
||||
QTest::newRow("valid deviceclass") << mockDeviceClassId << 5;
|
||||
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0;
|
||||
QTest::newRow("valid deviceclass") << mockDeviceClassId
|
||||
<< (QList<ActionTypeId>() << mockActionIdAsync << mockActionIdAsyncFailing << mockActionIdFailing << mockActionIdNoParams << mockActionIdPower << mockActionIdWithParams);
|
||||
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << QList<ActionTypeId>();
|
||||
}
|
||||
|
||||
void TestDevices::getActionTypes()
|
||||
{
|
||||
QFETCH(DeviceClassId, deviceClassId);
|
||||
QFETCH(int, resultCount);
|
||||
QFETCH(QList<ActionTypeId>, actionTypeTestData);
|
||||
|
||||
QVariantMap params;
|
||||
params.insert("deviceClassId", deviceClassId);
|
||||
QVariant response = injectAndWait("Devices.GetActionTypes", params);
|
||||
|
||||
QVariantList actionTypes = response.toMap().value("params").toMap().value("actionTypes").toList();
|
||||
QCOMPARE(actionTypes.count(), resultCount);
|
||||
if (resultCount > 0) {
|
||||
QCOMPARE(actionTypes.first().toMap().value("id").toString(), mockActionIdWithParams.toString());
|
||||
QCOMPARE(actionTypes.count(), actionTypeTestData.count());
|
||||
foreach (const ActionTypeId &testDataId, actionTypeTestData) {
|
||||
bool found = false;
|
||||
foreach (const QVariant &at, actionTypes) {
|
||||
if (testDataId.toString() == at.toMap().value("id").toString()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
QVERIFY(found);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -658,7 +670,7 @@ void TestDevices::getEventTypes_data()
|
|||
QTest::addColumn<DeviceClassId>("deviceClassId");
|
||||
QTest::addColumn<int>("resultCount");
|
||||
|
||||
QTest::newRow("valid deviceclass") << mockDeviceClassId << 4;
|
||||
QTest::newRow("valid deviceclass") << mockDeviceClassId << 7;
|
||||
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0;
|
||||
}
|
||||
|
||||
|
|
@ -683,7 +695,7 @@ void TestDevices::getStateTypes_data()
|
|||
QTest::addColumn<DeviceClassId>("deviceClassId");
|
||||
QTest::addColumn<int>("resultCount");
|
||||
|
||||
QTest::newRow("valid deviceclass") << mockDeviceClassId << 2;
|
||||
QTest::newRow("valid deviceclass") << mockDeviceClassId << 5;
|
||||
QTest::newRow("invalid deviceclass") << DeviceClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0;
|
||||
}
|
||||
|
||||
|
|
@ -784,7 +796,7 @@ void TestDevices::getStateValues()
|
|||
QCOMPARE(response.toMap().value("params").toMap().value("deviceError").toString(), JsonTypes::deviceErrorToString(statusCode));
|
||||
if (statusCode == DeviceManager::DeviceErrorNoError) {
|
||||
QVariantList values = response.toMap().value("params").toMap().value("values").toList();
|
||||
QCOMPARE(values.count(), 2); // Mock device has two states...
|
||||
QCOMPARE(values.count(), 5); // Mock device has two states...
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1231,6 +1243,8 @@ void TestDevices::removeAutoDevice()
|
|||
QVERIFY2(devices.count() > 0, "There needs to be at least one auto-created Mock Device for this test");
|
||||
device = devices.first();
|
||||
|
||||
DeviceClass dc = GuhCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
||||
|
||||
// trigger disappear signal in mock device
|
||||
spy.clear();
|
||||
port = device->paramValue(httpportParamTypeId).toInt();
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ EventTypeId mockEvent1Id = EventTypeId("45bf3752-0fc6-46b9-89fd-ffd878b5b22b");
|
|||
EventTypeId mockEvent2Id = EventTypeId("863d5920-b1cf-4eb9-88bd-8f7b8583b1cf");
|
||||
StateTypeId mockIntStateId = StateTypeId("80baec19-54de-4948-ac46-31eabfaceb83");
|
||||
StateTypeId mockBoolStateId = StateTypeId("9dd6a97c-dfd1-43dc-acbd-367932742310");
|
||||
StateTypeId mockBatteryCriticalStateId = StateTypeId("580bc611-1a55-41f3-996f-8d3ccf543db3");
|
||||
ActionTypeId mockActionIdPower = ActionTypeId("064aed0d-da4c-49d4-b236-60f97e98ff84");
|
||||
ActionTypeId mockActionIdWithParams = ActionTypeId("dea0f4e1-65e3-4981-8eaa-2701c53a9185");
|
||||
ActionTypeId mockActionIdNoParams = ActionTypeId("defd3ed6-1a0d-400b-8879-a0202cf39935");
|
||||
ActionTypeId mockActionIdAsync = ActionTypeId("fbae06d3-7666-483e-a39e-ec50fe89054e");
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ extern DeviceClassId mockDeviceDiscoveryClassId;
|
|||
extern DeviceClassId mockDeviceAsyncSetupClassId;
|
||||
extern DeviceClassId mockDeviceBrokenClassId;
|
||||
extern DeviceClassId mockDeviceBrokenAsyncSetupClassId;
|
||||
extern ActionTypeId mockActionIdPower;
|
||||
extern ActionTypeId mockActionIdWithParams;
|
||||
extern ActionTypeId mockActionIdNoParams;
|
||||
extern ActionTypeId mockActionIdAsync;
|
||||
|
|
@ -55,6 +56,7 @@ extern ActionTypeId mockActionIdAsyncFailing;
|
|||
extern EventTypeId mockEvent1Id;
|
||||
extern EventTypeId mockEvent2Id;
|
||||
extern StateTypeId mockIntStateId;
|
||||
extern StateTypeId mockBatteryCriticalStateId;
|
||||
extern StateTypeId mockBoolStateId;
|
||||
|
||||
// ParamTypes from mock devices
|
||||
|
|
|
|||
|
|
@ -99,6 +99,8 @@ private slots:
|
|||
void testRuleActionParams_data();
|
||||
void testRuleActionParams();
|
||||
|
||||
void testInterfaceBasedRule();
|
||||
|
||||
void testHousekeeping_data();
|
||||
void testHousekeeping();
|
||||
|
||||
|
|
@ -488,7 +490,7 @@ void TestRules::addRemoveRules_data()
|
|||
QTest::newRow("valid rule. diabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << false << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule";
|
||||
QTest::newRow("valid rule. 2 EventDescriptors, 1 Action, name") << true << validActionNoParams << QVariantMap() << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule";
|
||||
QTest::newRow("invalid action") << true << invalidAction << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorActionTypeNotFound << false << "TestRule";
|
||||
QTest::newRow("invalid event descriptor") << true << validActionNoParams << QVariantMap() << invalidEventDescriptor << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorDeviceNotFound << false << "TestRule";
|
||||
QTest::newRow("invalid event descriptor") << true << validActionNoParams << QVariantMap() << invalidEventDescriptor << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorEventTypeNotFound << false << "TestRule";
|
||||
QTest::newRow("invalid StateDescriptor") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << invalidStateEvaluator << RuleEngine::RuleErrorInvalidParameter << true << "TestRule";
|
||||
}
|
||||
|
||||
|
|
@ -2065,6 +2067,44 @@ void TestRules::testRuleActionParams()
|
|||
verifyRuleError(response, error);
|
||||
}
|
||||
|
||||
void TestRules::testInterfaceBasedRule()
|
||||
{
|
||||
QVariantMap powerAction;
|
||||
powerAction.insert("interface", "light");
|
||||
powerAction.insert("interfaceAction", "power");
|
||||
QVariantMap powerActionParam;
|
||||
powerActionParam.insert("paramName", "power");
|
||||
powerActionParam.insert("value", true);
|
||||
powerAction.insert("ruleActionParams", QVariantList() << powerActionParam);
|
||||
|
||||
QVariantMap lowBatteryEvent;
|
||||
lowBatteryEvent.insert("interface", "battery");
|
||||
lowBatteryEvent.insert("interfaceEvent", "batteryCritical");
|
||||
|
||||
QVariantMap addRuleParams;
|
||||
addRuleParams.insert("name", "TestInterfaceBasedRule");
|
||||
addRuleParams.insert("enabled", true);
|
||||
addRuleParams.insert("actions", QVariantList() << powerAction);
|
||||
addRuleParams.insert("eventDescriptors", QVariantList() << lowBatteryEvent);
|
||||
|
||||
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
|
||||
|
||||
|
||||
// Change the state
|
||||
QNetworkAccessManager nam;
|
||||
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
|
||||
|
||||
// state battery critical state to true
|
||||
qDebug() << "setting battery critical state to true";
|
||||
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBatteryCriticalStateId.toString()).arg(true)));
|
||||
QNetworkReply *reply = nam.get(request);
|
||||
spy.wait();
|
||||
QCOMPARE(spy.count(), 1);
|
||||
reply->deleteLater();
|
||||
|
||||
qDebug() << "response" << response;
|
||||
}
|
||||
|
||||
void TestRules::testHousekeeping_data()
|
||||
{
|
||||
QTest::addColumn<bool>("testAction");
|
||||
|
|
|
|||
Loading…
Reference in New Issue