add simple rule engine

This commit is contained in:
Michael Zanetti 2014-01-02 00:54:47 +01:00
parent c410aee890
commit e30a533391
18 changed files with 269 additions and 8 deletions

View File

@ -5,6 +5,11 @@ Action::Action(const QUuid &id) :
{
}
bool Action::isValid() const
{
return !m_id.isNull();
}
QUuid Action::id() const
{
return m_id;

View File

@ -7,7 +7,8 @@
class Action
{
public:
Action(const QUuid &id);
Action(const QUuid &id = QUuid());
bool isValid() const;
QUuid id() const;

View File

@ -95,6 +95,30 @@ DeviceClass DeviceManager::findDeviceClass(const QUuid &deviceClassId)
return DeviceClass(QUuid(), QUuid());
}
Trigger DeviceManager::findTrigger(const QUuid &triggerId)
{
foreach (Device *device, m_configuredDevices) {
foreach (const Trigger &trigger, device->triggers()) {
if (trigger.id() == triggerId) {
return trigger;
}
}
}
return Trigger();
}
Action DeviceManager::findAction(const QUuid &actionId)
{
foreach (Device *device, m_configuredDevices) {
foreach (const Action &action, device->actions()) {
if (action.id() == actionId) {
return action;
}
}
}
return Action();
}
Radio433 *DeviceManager::radio433() const
{
return m_radio433;

View File

@ -3,6 +3,7 @@
#include "deviceclass.h"
#include "trigger.h"
#include "action.h"
#include <QObject>
@ -32,6 +33,9 @@ public:
QList<Device*> findConfiguredDevices(const QUuid &deviceClassId);
DeviceClass findDeviceClass(const QUuid &deviceClassId);
Trigger findTrigger(const QUuid &triggerId);
Action findAction(const QUuid &actionId);
Radio433 *radio433() const;
signals:

View File

@ -5,6 +5,11 @@ Trigger::Trigger(const QUuid &id):
{
}
bool Trigger::isValid() const
{
return !m_id.isNull();
}
QUuid Trigger::id() const
{
return m_id;

View File

@ -8,7 +8,8 @@
class Trigger
{
public:
Trigger(const QUuid &id);
Trigger(const QUuid &id = QUuid());
bool isValid() const;
QUuid id() const;

View File

@ -1,6 +1,7 @@
#include "hivecore.h"
#include "jsonrpcserver.h"
#include "devicemanager.h"
#include "ruleengine.h"
#include <QDebug>
@ -19,15 +20,28 @@ DeviceManager *HiveCore::deviceManager() const
return m_deviceManager;
}
RuleEngine *HiveCore::ruleEngine() const
{
return m_ruleEngine;
}
HiveCore::HiveCore(QObject *parent) :
QObject(parent)
{
qDebug() << "creating devmanager";
qDebug() << "*****************************************";
qDebug() << "* Creating Device Manager *";
qDebug() << "*****************************************";
m_deviceManager = new DeviceManager(this);
qDebug() << "*****************************************";
qDebug() << "* Creating Rule Engine *";
qDebug() << "*****************************************";
m_ruleEngine = new RuleEngine(this);
// start the server
qDebug() << "*****************************************";
qDebug() << "* Starting JSON RPC Server *";
qDebug() << "*****************************************";
m_jsonServer = new JsonRPCServer(this);
connect(m_deviceManager,SIGNAL(emitTrigger(QUuid,QVariantMap)),this,SLOT(gotSignal(QUuid,QVariantMap)));
@ -40,4 +54,7 @@ void HiveCore::gotSignal(const QUuid &triggerId, const QVariantMap &params)
qDebug() << "id: " << triggerId;
qDebug() << params;
foreach (const QUuid &actionId, m_ruleEngine->evaluateTrigger(triggerId)) {
m_deviceManager->executeAction(actionId, params);
}
}

View File

@ -1,10 +1,13 @@
#ifndef HIVECORE_H
#define HIVECORE_H
#include "rule.h"
#include <QObject>
class JsonRPCServer;
class DeviceManager;
class RuleEngine;
class HiveCore : public QObject
{
@ -13,6 +16,7 @@ public:
static HiveCore* instance();
DeviceManager* deviceManager() const;
RuleEngine *ruleEngine() const;
private:
explicit HiveCore(QObject *parent = 0);
@ -20,6 +24,7 @@ private:
JsonRPCServer *m_jsonServer;
DeviceManager *m_deviceManager;
RuleEngine *m_ruleEngine;
private slots:
void gotSignal(const QUuid &triggerId, const QVariantMap &params);

View File

@ -6,6 +6,8 @@
#include "devicemanager.h"
#include "deviceclass.h"
#include "device.h"
#include "rule.h"
#include "ruleengine.h"
#include <QJsonDocument>
#include <QStringList>
@ -75,21 +77,54 @@ void JsonRPCServer::processData(int clientId, const QByteArray &jsonData)
break;
}
} else if (method == "GetConfiguredDevices") {
QVariantMap params;
QVariantMap rspParams;
QVariantList configuredDeviceList;
foreach (Device *device, HiveCore::instance()->deviceManager()->configuredDevices()) {
configuredDeviceList.append(packDevice(device));
}
params.insert("devices", configuredDeviceList);
sendResponse(clientId, commandId, params);
rspParams.insert("devices", configuredDeviceList);
sendResponse(clientId, commandId, rspParams);
} else {
sendErrorResponse(clientId, commandId, "No such method");
}
} else if (targetNamspace == "Rules") {
handleRulesMessage(clientId, commandId, method, params);
} else {
qDebug() << "got unknown namespace" << targetNamspace;
}
}
void JsonRPCServer::handleRulesMessage(int clientId, int commandId, const QString &method, const QVariantMap &params)
{
if (method == "GetRules") {
QVariantList rulesList;
foreach (const Rule &rule, HiveCore::instance()->ruleEngine()->rules()) {
QVariantMap ruleMap;
ruleMap.insert("id", rule.id());
ruleMap.insert("triggerId", rule.triggerId());
ruleMap.insert("actionId", rule.actionId());
rulesList.append(ruleMap);
}
QVariantMap rspParams;
rspParams.insert("rules", rulesList);
sendResponse(clientId, commandId, rspParams);
} else if (method == "AddRule") {
QUuid triggerId = params.value("triggerId").toUuid();
QUuid actionId = params.value("actionId").toUuid();
switch(HiveCore::instance()->ruleEngine()->addRule(triggerId, actionId)) {
case RuleEngine::RuleErrorNoError:
sendResponse(clientId, commandId);
break;
case RuleEngine::RuleErrorNoSuchTrigger:
sendErrorResponse(clientId, commandId, "No such trigger");
break;
case RuleEngine::RuleErrorNoSuchAction:
sendErrorResponse(clientId, commandId, "No such action");
break;
}
}
}
QVariantMap JsonRPCServer::packDeviceClass(const DeviceClass &deviceClass)
{
QVariantMap variant;

View File

@ -23,6 +23,8 @@ private slots:
void processData(int clientId, const QByteArray &jsonData);
private:
void handleRulesMessage(int clientId, int commandId, const QString &method, const QVariantMap &params);
QVariantMap packDeviceClass(const DeviceClass &deviceClass);
QVariantMap packDevice(Device *device);

23
server/rule.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "rule.h"
Rule::Rule(const QUuid &id, const QUuid &triggerId, const QUuid &actionId):
m_id(id),
m_triggerId(triggerId),
m_actionId(actionId)
{
}
QUuid Rule::id() const
{
return m_id;
}
QUuid Rule::triggerId() const
{
return m_triggerId;
}
QUuid Rule::actionId() const
{
return m_actionId;
}

21
server/rule.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef RULE_H
#define RULE_H
#include <QUuid>
class Rule
{
public:
Rule(const QUuid &id, const QUuid &triggerId, const QUuid &actionId);
QUuid id() const;
QUuid triggerId() const;
QUuid actionId() const;
private:
QUuid m_id;
QUuid m_triggerId;
QUuid m_actionId;
};
#endif // RULE_H

64
server/ruleengine.cpp Normal file
View File

@ -0,0 +1,64 @@
#include "ruleengine.h"
#include "hivecore.h"
#include "devicemanager.h"
#include <QSettings>
#include <QDebug>
#include <QStringList>
#include <QStandardPaths>
QString rulesFileName = "hiveyourhome/rules";
RuleEngine::RuleEngine(QObject *parent) :
QObject(parent)
{
QSettings settings(rulesFileName);
qDebug() << "loading rules from" << rulesFileName;
foreach (const QString &idString, settings.childGroups()) {
qDebug() << "found rule" << idString;
settings.beginGroup(idString);
Rule rule = Rule(QUuid(idString), settings.value("triggerId").toUuid(), settings.value("actionId").toUuid());
settings.endGroup();
m_rules.append(rule);
}
}
QList<QUuid> RuleEngine::evaluateTrigger(const QUuid &triggerId)
{
QList<QUuid> actions;
for (int i = 0; i < m_rules.count(); ++i) {
if (m_rules.at(i).triggerId() == triggerId) {
actions << m_rules.at(i).actionId();
}
}
return actions;
}
RuleEngine::RuleError RuleEngine::addRule(const QUuid &triggerId, const QUuid &actionId)
{
if (!HiveCore::instance()->deviceManager()->findTrigger(triggerId).isValid()) {
qWarning() << "Cannot create rule. No such trigger.";
return RuleErrorNoSuchTrigger;
}
if (!HiveCore::instance()->deviceManager()->findAction(actionId).isValid()) {
qWarning() << "Cannot create rule. No such action.";
return RuleErrorNoSuchAction;
}
Rule rule = Rule(QUuid::createUuid(), triggerId, actionId);
m_rules.append(rule);
QSettings settings(rulesFileName);
settings.beginGroup(rule.id().toString());
settings.setValue("triggerId", rule.triggerId());
settings.setValue("actionId", rule.actionId());
return RuleErrorNoError;
}
QList<Rule> RuleEngine::rules() const
{
return m_rules;
}

32
server/ruleengine.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef RULEENGINE_H
#define RULEENGINE_H
#include "rule.h"
#include <QObject>
#include <QList>
#include <QUuid>
class RuleEngine : public QObject
{
Q_OBJECT
public:
enum RuleError {
RuleErrorNoError,
RuleErrorNoSuchTrigger,
RuleErrorNoSuchAction
};
explicit RuleEngine(QObject *parent = 0);
QList<QUuid> evaluateTrigger(const QUuid &triggerId);
RuleError addRule(const QUuid &triggerId, const QUuid &actionId);
QList<Rule> rules() const;
private:
QList<Rule> m_rules;
};
#endif // RULEENGINE_H

View File

@ -14,10 +14,14 @@ SOURCES += main.cpp \
hivecore.cpp \
jsonrpcserver.cpp \
tcpserver.cpp \
ruleengine.cpp \
rule.cpp
HEADERS += hivecore.h \
jsonrpcserver.h \
tcpserver.h \
ruleengine.h \
rule.h
# FIXME: Drop this and link them dynamically
LIBS += -L../plugins/deviceplugins/rfremotemumbi/ -lhive_rfremotemumbi

7
tests/addrule.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
if test -z $3; then
echo "usage: $1 host triggerId actionId"
else
(echo '{"id":1, "method":"Rules.AddRule", "params":{"triggerId": "$2", "actionId":"$3" }}'; sleep 1) | nc $1 1234
fi

View File

@ -1,3 +1,7 @@
#!/bin/bash
(echo '{"id":1, "method":"Devices.GetConfiguredDevices"}'; sleep 1) | nc 10.10.10.114 1234
if [ -z $1 ]; then
echo "usage: $0 host"
else
(echo '{"id":1, "method":"Devices.GetConfiguredDevices"}'; sleep 1) | nc $1 1234
fi

7
tests/getrules.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
if [ -z $1 ]; then
echo "usage: $0 host"
else
(echo '{"id":1, "method":"Rules.GetRules"}'; sleep 1) | nc $1 1234
fi