add simple rule engine
This commit is contained in:
parent
c410aee890
commit
e30a533391
@ -5,6 +5,11 @@ Action::Action(const QUuid &id) :
|
||||
{
|
||||
}
|
||||
|
||||
bool Action::isValid() const
|
||||
{
|
||||
return !m_id.isNull();
|
||||
}
|
||||
|
||||
QUuid Action::id() const
|
||||
{
|
||||
return m_id;
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
class Action
|
||||
{
|
||||
public:
|
||||
Action(const QUuid &id);
|
||||
Action(const QUuid &id = QUuid());
|
||||
bool isValid() const;
|
||||
|
||||
QUuid id() const;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -5,6 +5,11 @@ Trigger::Trigger(const QUuid &id):
|
||||
{
|
||||
}
|
||||
|
||||
bool Trigger::isValid() const
|
||||
{
|
||||
return !m_id.isNull();
|
||||
}
|
||||
|
||||
QUuid Trigger::id() const
|
||||
{
|
||||
return m_id;
|
||||
|
||||
@ -8,7 +8,8 @@
|
||||
class Trigger
|
||||
{
|
||||
public:
|
||||
Trigger(const QUuid &id);
|
||||
Trigger(const QUuid &id = QUuid());
|
||||
bool isValid() const;
|
||||
|
||||
QUuid id() const;
|
||||
|
||||
|
||||
@ -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 ¶ms)
|
||||
qDebug() << "id: " << triggerId;
|
||||
qDebug() << params;
|
||||
|
||||
foreach (const QUuid &actionId, m_ruleEngine->evaluateTrigger(triggerId)) {
|
||||
m_deviceManager->executeAction(actionId, params);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 ¶ms);
|
||||
|
||||
@ -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 ¶ms)
|
||||
{
|
||||
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;
|
||||
|
||||
@ -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 ¶ms);
|
||||
|
||||
QVariantMap packDeviceClass(const DeviceClass &deviceClass);
|
||||
QVariantMap packDevice(Device *device);
|
||||
|
||||
|
||||
23
server/rule.cpp
Normal file
23
server/rule.cpp
Normal 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
21
server/rule.h
Normal 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
64
server/ruleengine.cpp
Normal 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
32
server/ruleengine.h
Normal 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
|
||||
@ -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
7
tests/addrule.sh
Executable 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
|
||||
@ -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
7
tests/getrules.sh
Executable 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
|
||||
Reference in New Issue
Block a user