reworked jsonrpc server.

added introspection
all calls and responses have now param validation
This commit is contained in:
Michael Zanetti 2014-01-20 01:13:43 +01:00
parent 693519841f
commit 02c8e6e4b4
26 changed files with 1252 additions and 355 deletions

View File

@ -1,19 +1,19 @@
#include "action.h"
Action::Action(const QUuid &deviceId, const QUuid &id) :
m_id(id),
Action::Action(const QUuid &deviceId, const QUuid &actionTypeId) :
m_actionTypeId(actionTypeId),
m_deviceId(deviceId)
{
}
bool Action::isValid() const
{
return !m_id.isNull();
return !m_actionTypeId.isNull() && !m_deviceId.isNull();
}
QUuid Action::id() const
QUuid Action::actionTypeId() const
{
return m_id;
return m_actionTypeId;
}
QUuid Action::deviceId() const
@ -21,16 +21,6 @@ QUuid Action::deviceId() const
return m_deviceId;
}
QString Action::name() const
{
return m_name;
}
void Action::setName(const QString &name)
{
m_name = name;
}
QVariantMap Action::params() const
{
return m_params;

View File

@ -7,23 +7,19 @@
class Action
{
public:
explicit Action(const QUuid &deviceId, const QUuid &id = QUuid::createUuid());
explicit Action(const QUuid &deviceId, const QUuid &actionTypeId);
bool isValid() const;
QUuid id() const;
QUuid actionTypeId() const;
QUuid deviceId() const;
QString name() const;
void setName(const QString &name);
QVariantMap params() const;
void setParams(const QVariantMap &params);
private:
QUuid m_id;
QUuid m_actionTypeId;
QUuid m_deviceId;
QString m_name;
QVariantMap m_params;
};

View File

@ -132,6 +132,20 @@ DeviceManager::DeviceError DeviceManager::executeAction(const Action &action)
{
foreach (Device *device, m_configuredDevices) {
if (action.deviceId() == device->id()) {
// found device
// Make sure this device has an action type with this id
DeviceClass deviceClass = findDeviceClass(device->deviceClassId());
bool found = false;
foreach (const ActionType &actionType, deviceClass.actions()) {
if (actionType.id() == action.actionTypeId()) {
found = true;
}
}
if (!found) {
return DeviceErrorActionTypeNotFound;
}
m_devicePlugins.value(device->pluginId())->executeAction(device, action);
return DeviceErrorNoError;
}

View File

@ -28,6 +28,7 @@ public:
DeviceErrorNoError,
DeviceErrorDeviceNotFound,
DeviceErrorDeviceClassNotFound,
DeviceErrorActionTypeNotFound,
DeviceErrorMissingParameter,
DeviceErrorPluginNotFound,
DeviceErrorSetupFailed

View File

@ -3,4 +3,4 @@ SUBDIRS += elro \
intertechno \
meisteranker \
wifidetector \
# boblight \

View File

@ -0,0 +1,62 @@
#include "actionhandler.h"
#include "devicemanager.h"
#include "hivecore.h"
#include "action.h"
#include <QDebug>
ActionHandler::ActionHandler(QObject *parent) :
JsonHandler(parent)
{
QVariantMap params;
QVariantMap returns;
params.clear(); returns.clear();
setDescription("ExecuteAction", "Execute a single action.");
params.insert("actionTypeId", "uuid");
params.insert("deviceId", "uuid");
params.insert("params", JsonTypes::paramTypeRef());
setParams("ExecuteAction", JsonTypes::actionDescription());
returns.insert("success", "bool");
returns.insert("errorMessage", "string");
setReturns("ExecuteAction", returns);
}
QString ActionHandler::name() const
{
return "Actions";
}
QVariantMap ActionHandler::ExecuteAction(const QVariantMap &params)
{
QUuid deviceId = params.value("deviceId").toUuid();
QUuid actionTypeId = params.value("actionTypeId").toUuid();
QVariantMap actionParams = params.value("params").toMap();
Action action(deviceId, actionTypeId);
action.setParams(actionParams);
qDebug() << "actions params in json" << action.params() << params;
QVariantMap returns;
DeviceManager::DeviceError error = HiveCore::instance()->deviceManager()->executeAction(action);
switch (error) {
case DeviceManager::DeviceErrorNoError:
returns.insert("success", true);
returns.insert("errorMessage", "");
break;
case DeviceManager::DeviceErrorDeviceNotFound:
returns.insert("errorMessage", "No such device");
returns.insert("success", false);
break;
default:
returns.insert("errorMessage", "Unknown error.");
returns.insert("success", false);
}
return returns;
}

View File

@ -0,0 +1,17 @@
#ifndef ACTIONHANDLER_H
#define ACTIONHANDLER_H
#include "jsonhandler.h"
class ActionHandler : public JsonHandler
{
Q_OBJECT
public:
explicit ActionHandler(QObject *parent = 0);
QString name() const;
Q_INVOKABLE QVariantMap ExecuteAction(const QVariantMap &params);
};
#endif // ACTIONHANDLER_H

View File

@ -0,0 +1,184 @@
#include "devicehandler.h"
#include "deviceclass.h"
#include "hivecore.h"
#include "devicemanager.h"
#include "deviceplugin.h"
DeviceHandler::DeviceHandler(QObject *parent) :
JsonHandler(parent)
{
QVariantMap returns;
QVariantMap params;
params.clear(); returns.clear();
setDescription("GetSupportedDevices", "Returns a list of supported Device classes.");
setParams("GetSupportedDevices", params);
QVariantList deviceClasses;
deviceClasses.append(JsonTypes::deviceClassRef());
returns.insert("deviceClasses", deviceClasses);
setReturns("GetSupportedDevices", returns);
params.clear(); returns.clear();
setDescription("GetPlugins", "Returns a list of loaded plugins.");
setParams("GetPlugins", params);
QVariantList plugins;
plugins.append(JsonTypes::pluginTypeRef());
returns.insert("plugins", plugins);
setReturns("GetPlugins", returns);
params.clear(); returns.clear();
setDescription("SetPluginParams", "Set a plugin's params.");
params.insert("pluginId", "uuid");
QVariantList pluginParams;
pluginParams.append(JsonTypes::paramTypeRef());
params.insert("pluginParams", pluginParams);
setParams("SetPluginParams", params);
setReturns("SetPluginParams", returns);
params.clear(); returns.clear();
setDescription("AddConfiguredDevice", "Add a configured device.");
params.insert("deviceClassId", "uuid");
QVariantList deviceParams;
deviceParams.append(JsonTypes::paramRef());
params.insert("deviceParams", deviceParams);
setParams("AddConfiguredDevice", params);
returns.insert("success", "bool");
returns.insert("errorMessage", "string");
setReturns("AddConfiguredDevice", returns);
params.clear(); returns.clear();
setDescription("GetConfiguredDevices", "Returns a list of configured devices.");
setParams("GetConfiguredDevices", params);
QVariantList devices;
devices.append(JsonTypes::deviceRef());
returns.insert("devices", devices);
setReturns("GetConfiguredDevices", returns);
params.clear(); returns.clear();
setDescription("GetTriggerTypes", "Get trigger types for a specified deviceClassId.");
params.insert("deviceClassId", "uuid");
setParams("GetTriggerTypes", params);
QVariantList triggers;
triggers.append(JsonTypes::triggerTypeRef());
returns.insert("triggerTypes", triggers);
setReturns("GetTriggerTypes", returns);
params.clear(); returns.clear();
setDescription("GetActionTypes", "Get action types for a specified deviceClassId.");
params.insert("deviceClassId", "uuid");
setParams("GetActionTypes", params);
QVariantList actions;
actions.append(JsonTypes::actionTypeRef());
returns.insert("actionTypes", actions);
setReturns("GetActionTypes", returns);
}
QString DeviceHandler::name() const
{
return "Devices";
}
QVariantMap DeviceHandler::GetSupportedDevices(const QVariantMap &params) const
{
Q_UNUSED(params)
QVariantMap returns;
QVariantList supportedDeviceList;
foreach (const DeviceClass &deviceClass, HiveCore::instance()->deviceManager()->supportedDevices()) {
supportedDeviceList.append(JsonTypes::packDeviceClass(deviceClass));
}
returns.insert("deviceClasses", supportedDeviceList);
return returns;
}
QVariantMap DeviceHandler::GetPlugins(const QVariantMap &params) const
{
Q_UNUSED(params)
QVariantMap returns;
QVariantList plugins;
foreach (DevicePlugin *plugin, HiveCore::instance()->deviceManager()->plugins()) {
QVariantMap pluginMap;
pluginMap.insert("id", plugin->pluginId());
pluginMap.insert("name", plugin->pluginName());
pluginMap.insert("params", plugin->configuration());
plugins.append(pluginMap);
}
returns.insert("plugins", plugins);
return returns;
}
QVariantMap DeviceHandler::SetPluginParams(const QVariantMap &params)
{
QUuid pluginId = params.value("pluginId").toUuid();
QVariantMap pluginParams = params.value("pluginParams").toMap();
HiveCore::instance()->deviceManager()->plugin(pluginId)->setConfiguration(pluginParams);
return QVariantMap();
}
QVariantMap DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
{
QUuid deviceClass = params.value("deviceClassId").toUuid();
QVariantMap deviceParams = params.value("deviceParams").toMap();
DeviceManager::DeviceError status = HiveCore::instance()->deviceManager()->addConfiguredDevice(deviceClass, deviceParams);
QVariantMap returns;
switch(status) {
case DeviceManager::DeviceErrorNoError:
returns.insert("success", true);
break;
case DeviceManager::DeviceErrorDeviceClassNotFound:
returns.insert("errorMessage", "Error creating device. Device class not found.");
returns.insert("success", false);
break;
case DeviceManager::DeviceErrorMissingParameter:
returns.insert("errorMessage", "Error creating device. Missing parameter.");
returns.insert("success", false);
break;
case DeviceManager::DeviceErrorSetupFailed:
returns.insert("errorMessage", "Error creating device. Device setup failed.");
returns.insert("success", false);
break;
default:
returns.insert("errorMessage", "Unknown error.");
returns.insert("success", false);
}
return returns;
}
QVariantMap DeviceHandler::GetConfiguredDevices(const QVariantMap &params) const
{
Q_UNUSED(params)
QVariantMap returns;
QVariantList configuredDeviceList;
foreach (Device *device, HiveCore::instance()->deviceManager()->configuredDevices()) {
configuredDeviceList.append(JsonTypes::packDevice(device));
}
returns.insert("devices", configuredDeviceList);
return returns;
}
QVariantMap DeviceHandler::GetTriggerTypes(const QVariantMap &params) const
{
QVariantMap returns;
QVariantList triggerList;
DeviceClass deviceClass = HiveCore::instance()->deviceManager()->findDeviceClass(params.value("deviceClassId").toUuid());
foreach (const TriggerType &triggerType, deviceClass.triggers()) {
triggerList.append(JsonTypes::packTriggerType(triggerType));
}
returns.insert("triggerTypes", triggerList);
return returns;
}
QVariantMap DeviceHandler::GetActionTypes(const QVariantMap &params) const
{
QVariantMap returns;
QVariantList actionList;
DeviceClass deviceClass = HiveCore::instance()->deviceManager()->findDeviceClass(params.value("deviceClassId").toUuid());
foreach (const ActionType &actionType, deviceClass.actions()) {
actionList.append(JsonTypes::packActionType(actionType));
}
returns.insert("actionTypes", actionList);
return returns;
}

View File

@ -0,0 +1,30 @@
#ifndef DEVICEHANDLER_H
#define DEVICEHANDLER_H
#include "jsonhandler.h"
class DeviceHandler : public JsonHandler
{
Q_OBJECT
public:
explicit DeviceHandler(QObject *parent = 0);
QString name() const override;
Q_INVOKABLE QVariantMap GetSupportedDevices(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap GetPlugins(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap SetPluginParams(const QVariantMap &params);
Q_INVOKABLE QVariantMap AddConfiguredDevice(const QVariantMap &params);
Q_INVOKABLE QVariantMap GetConfiguredDevices(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap GetTriggerTypes(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap GetActionTypes(const QVariantMap &params) const;
};
#endif // DEVICEHANDLER_H

View File

@ -0,0 +1,81 @@
#include "jsonhandler.h"
#include <QMetaMethod>
#include <QDebug>
JsonHandler::JsonHandler(QObject *parent) :
QObject(parent)
{
}
QVariantMap JsonHandler::introspect()
{
QVariantMap data;
for (int i = 0; i < metaObject()->methodCount(); ++i) {
QMetaMethod method = metaObject()->method(i);
if (method.methodType() == QMetaMethod::Method) {
QVariantMap methodData;
if (!m_descriptions.contains(method.name()) || !m_params.contains(method.name()) || !m_returns.contains(method.name())) {
continue;
}
methodData.insert("description", m_descriptions.value(method.name()));
methodData.insert("params", m_params.value(method.name()));
methodData.insert("returns", m_returns.value(method.name()));
data.insert(name() + "." + method.name(), methodData);
}
}
return data;
}
bool JsonHandler::hasMethod(const QString &methodName)
{
return m_descriptions.contains(methodName) && m_params.contains(methodName) && m_returns.contains(methodName);
}
bool JsonHandler::validateParams(const QString &methodName, const QVariantMap &params)
{
QVariantMap paramTemplate = m_params.value(methodName);
return JsonTypes::validateMap(paramTemplate, params);
}
bool JsonHandler::validateReturns(const QString &methodName, const QVariantMap &returns)
{
QVariantMap returnsTemplate = m_returns.value(methodName);
return JsonTypes::validateMap(returnsTemplate, returns);
}
void JsonHandler::setDescription(const QString &methodName, const QString &description)
{
for(int i = 0; i < metaObject()->methodCount(); ++i) {
QMetaMethod method = metaObject()->method(i);
if (method.name() == methodName) {
m_descriptions.insert(methodName, description);
return;
}
}
qWarning() << "Cannot set description. No such method:" << methodName;
}
void JsonHandler::setParams(const QString &methodName, const QVariantMap &params)
{
for(int i = 0; i < metaObject()->methodCount(); ++i) {
QMetaMethod method = metaObject()->method(i);
if (method.name() == methodName) {
m_params.insert(methodName, params);
return;
}
}
qWarning() << "Cannot set params. No such method:" << methodName;
}
void JsonHandler::setReturns(const QString &methodName, const QVariantMap &returns)
{
for(int i = 0; i < metaObject()->methodCount(); ++i) {
QMetaMethod method = metaObject()->method(i);
if (method.name() == methodName) {
m_returns.insert(methodName, returns);
return;
}
}
qWarning() << "Cannot set returns. No such method:" << methodName;
}

View File

@ -0,0 +1,34 @@
#ifndef JSONHANDLER_H
#define JSONHANDLER_H
#include "jsontypes.h"
#include <QObject>
#include <QVariantMap>
class JsonHandler : public QObject
{
Q_OBJECT
public:
explicit JsonHandler(QObject *parent = 0);
virtual QString name() const = 0;
QVariantMap introspect();
bool hasMethod(const QString &methodName);
bool validateParams(const QString &methodName, const QVariantMap &params);
bool validateReturns(const QString &methodName, const QVariantMap &returns);
protected:
void setDescription(const QString &methodName, const QString &description);
void setParams(const QString &methodName, const QVariantMap &params);
void setReturns(const QString &methodName, const QVariantMap &returns);
private:
QHash<QString, QString> m_descriptions;
QHash<QString, QVariantMap> m_params;
QHash<QString, QVariantMap> m_returns;
};
#endif // JSONHANDLER_H

View File

@ -0,0 +1,128 @@
#include "jsonrpcserver.h"
#include "jsontypes.h"
#include "tcpserver.h"
#include "jsonhandler.h"
#include "hivecore.h"
#include "devicemanager.h"
#include "deviceplugin.h"
#include "deviceclass.h"
#include "device.h"
#include "rule.h"
#include "ruleengine.h"
#include "devicehandler.h"
#include "actionhandler.h"
#include "ruleshandler.h"
#include <QJsonDocument>
#include <QStringList>
JsonRPCServer::JsonRPCServer(QObject *parent):
QObject(parent),
m_tcpServer(new TcpServer(this))
{
connect(m_tcpServer, &TcpServer::jsonDataAvailable, this, &JsonRPCServer::processData);
m_tcpServer->startServer();
registerHandler(new DeviceHandler(this));
registerHandler(new ActionHandler(this));
registerHandler(new RulesHandler(this));
}
void JsonRPCServer::processData(int clientId, const QByteArray &jsonData)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &error);
if(error.error != QJsonParseError::NoError) {
qDebug() << "failed to parse data" << jsonData << ":" << error.errorString();
}
qDebug() << "-------------------------\n" << jsonDoc.toJson();
QVariantMap message = jsonDoc.toVariant().toMap();
bool success;
int commandId = message.value("id").toInt(&success);
if (!success) {
qWarning() << "Error parsing command. Missing \"id\":" << jsonData;
return;
}
QStringList commandList = message.value("method").toString().split('.');
if (commandList.count() != 2) {
qWarning() << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\"";
return;
}
QString targetNamespace = commandList.first();
QString method = commandList.last();
QVariantMap params = message.value("params").toMap();
qDebug() << "got:" << targetNamespace << method << params;
emit commandReceived(targetNamespace, method, params);
if (targetNamespace == "JSONRPC") {
if (method == "Introspect") {
QVariantMap data;
data.insert("types", JsonTypes::allTypes());
QVariantMap methods;
foreach (JsonHandler *handler, m_handlers) {
qDebug() << "got handler" << handler->name() << handler->introspect();
methods.unite(handler->introspect());
}
data.insert("methods", methods);
sendResponse(clientId, commandId, data);
return;
}
}
JsonHandler *handler = m_handlers.value(targetNamespace);
if (!handler) {
sendErrorResponse(clientId, commandId, "No such namespace");
return;
}
if (!handler->hasMethod(method)) {
sendErrorResponse(clientId, commandId, "No such method");
return;
}
if (!handler->validateParams(method, params)) {
sendErrorResponse(clientId, commandId, "Invalid params");
return;
}
QVariantMap returns;
QMetaObject::invokeMethod(handler, method.toLatin1().data(), Q_RETURN_ARG(QVariantMap, returns), Q_ARG(QVariantMap, params));
Q_ASSERT(handler->validateReturns(method, returns));
sendResponse(clientId, commandId, returns);
}
void JsonRPCServer::registerHandler(JsonHandler *handler)
{
m_handlers.insert(handler->name(), handler);
}
void JsonRPCServer::sendResponse(int clientId, int commandId, const QVariantMap &params)
{
QVariantMap rsp;
rsp.insert("id", commandId);
rsp.insert("status", "success");
rsp.insert("params", params);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(rsp);
m_tcpServer->sendResponse(clientId, jsonDoc.toJson());
}
void JsonRPCServer::sendErrorResponse(int clientId, int commandId, const QString &error)
{
QVariantMap rsp;
rsp.insert("id", commandId);
rsp.insert("status", "error");
rsp.insert("error", error);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(rsp);
m_tcpServer->sendResponse(clientId, jsonDoc.toJson());
}

View File

@ -11,6 +11,7 @@
class TcpServer;
class Device;
class JsonHandler;
class JsonRPCServer: public QObject
{
@ -25,20 +26,14 @@ private slots:
void processData(int clientId, const QByteArray &jsonData);
private:
void handleDevicesMessage(int clientId, int commandId, const QString &method, const QVariantMap &params);
void handleRulesMessage(int clientId, int commandId, const QString &method, const QVariantMap &params);
void handleActionMessage(int clientId, int commandId, const QString &method, const QVariantMap &params);
QVariantMap packDeviceClass(const DeviceClass &deviceClass);
QVariantMap packDevice(Device *device);
QVariantMap packTrigger(const Trigger &action);
QVariantMap packAction(const Action &action);
void registerHandler(JsonHandler *handler);
void sendResponse(int clientId, int commandId, const QVariantMap &params = QVariantMap());
void sendErrorResponse(int clientId, int commandId, const QString &error);
private:
TcpServer *m_tcpServer;
QHash<QString, JsonHandler*> m_handlers;
};
#endif

View File

@ -0,0 +1,449 @@
#include "jsontypes.h"
#include "device.h"
#include <QDebug>
namespace JsonTypes {
QVariantMap allTypes()
{
QVariantMap allTypes;
allTypes.insert("BasicType", basicTypes());
allTypes.insert("ParamType", paramTypeDescription());
allTypes.insert("StateType", stateTypeDescription());
allTypes.insert("TriggerType", triggerTypeDescription());
allTypes.insert("ActionType", actionTypeDescription());
allTypes.insert("DeviceClass", deviceClassDescription());
allTypes.insert("PluginType", pluginTypeDescription());
allTypes.insert("Param", paramDescription());
allTypes.insert("Trigger", triggerDescription());
allTypes.insert("Device", deviceDescription());
allTypes.insert("Action", actionDescription());
return allTypes;
}
QString basicTypesRef()
{
return "$ref:BasicType";
}
QVariantList basicTypes()
{
QVariantList basicTypes;
basicTypes.append("uuid");
basicTypes.append("string");
basicTypes.append("integer");
basicTypes.append("double");
basicTypes.append("bool");
return basicTypes;
}
QString paramTypeRef()
{
return "$ref:ParamType";
}
QVariantMap paramTypeDescription()
{
QVariantMap paramType;
paramType.insert("name", "string");
paramType.insert("type", basicTypesRef());
// paramType.insert("default", "value");
// paramType.insert("value", "value");
return paramType;
}
QString paramRef()
{
return "$ref:Param";
}
QVariantMap paramDescription()
{
QVariantMap param;
param.insert("name", "string");
param.insert("value", basicTypesRef());
return param;
}
QString stateTypeRef()
{
return "$ref:StateType";
}
QVariantMap stateTypeDescription()
{
QVariantMap stateTypeDescription;
stateTypeDescription.insert("id", "uuid");
stateTypeDescription.insert("name", "string");
stateTypeDescription.insert("type", basicTypesRef());
// stateTypeDescription.insert("default", "value");
return stateTypeDescription;
}
QString triggerTypeRef()
{
return "$ref:TriggerType";
}
QVariantMap triggerTypeDescription()
{
QVariantMap triggerTypeDescription;
triggerTypeDescription.insert("id", "uuid");
triggerTypeDescription.insert("name", "string");
QVariantList params;
params.append(paramTypeRef());
triggerTypeDescription.insert("params", params);
return triggerTypeDescription;
}
QVariantMap packTriggerType(const TriggerType &triggerType)
{
QVariantMap variant;
variant.insert("id", triggerType.id());
variant.insert("name", triggerType.name());
variant.insert("params", triggerType.parameters());
return variant;
}
QString triggerRef()
{
return "$ref:Trigger";
}
QVariantMap triggerDescription()
{
QVariantMap triggerDescription;
triggerDescription.insert("triggerTypeId", "uuid");
triggerDescription.insert("deviceId", "uuid");
QVariantList params;
params.append(paramRef());
triggerDescription.insert("params", params);
return triggerDescription;
}
QVariantMap packTrigger(const Trigger &trigger)
{
QVariantMap variant;
variant.insert("id", trigger.triggerTypeId());
variant.insert("deviceId", trigger.deviceId());
variant.insert("params", trigger.params());
return variant;
}
QString actionTypeRef()
{
return "$ref:ActionType";
}
QVariantMap actionTypeDescription()
{
QVariantMap actionTypeDescription;
actionTypeDescription.insert("id", "uuid");
actionTypeDescription.insert("name", "string");
QVariantList params;
params.append(paramTypeRef());
actionTypeDescription.insert("params", params);
return actionTypeDescription;
}
QVariantMap packActionType(const ActionType &actionType)
{
QVariantMap variantMap;
variantMap.insert("id", actionType.id());
variantMap.insert("name", actionType.name());
variantMap.insert("params", actionType.parameters());
return variantMap;
}
QString actionRef()
{
return "$ref:Action";
}
QVariantMap actionDescription()
{
QVariantMap actionDescription;
actionDescription.insert("actionTypeId", "uuid");
actionDescription.insert("deviceId", "uuid");
QVariantList params;
params.append(paramRef());
actionDescription.insert("params", params);
return actionDescription;
}
QVariantMap packAction(const Action &action)
{
QVariantMap variant;
variant.insert("actionTypeId", action.actionTypeId());
variant.insert("deviceId", action.deviceId());
variant.insert("params", action.params());
return variant;
}
QString deviceClassRef()
{
return "$ref:DeviceClass";
}
QVariantMap deviceClassDescription()
{
QVariantMap deviceClass;
deviceClass.insert("id", "uuid");
deviceClass.insert("name", "string");
QVariantList states;
states.append(stateTypeRef());
deviceClass.insert("states", states);
QVariantList triggers;
triggers.append(triggerTypeRef());
deviceClass.insert("triggers", triggers);
QVariantList actions;
actions.append(actionTypeRef());
deviceClass.insert("actions", actions);
QVariantList params;
params.append(paramTypeRef());
deviceClass.insert("params", params);
return deviceClass;
}
QVariantMap packDeviceClass(const DeviceClass &deviceClass)
{
QVariantMap variant;
variant.insert("name", deviceClass.name());
variant.insert("id", deviceClass.id());
QVariantList stateTypes;
foreach (const StateType &stateType, deviceClass.states()) {
QVariantMap stateMap;
stateMap.insert("id", stateType.id().toString());
stateMap.insert("name", stateType.name());
stateMap.insert("type", QVariant::typeToName(stateType.type()));
stateTypes.append(stateMap);
}
QVariantList triggerTypes;
foreach (const TriggerType &triggerType, deviceClass.triggers()) {
QVariantMap triggerMap;
triggerMap.insert("id", triggerType.id().toString());
triggerMap.insert("name", triggerType.name());
triggerMap.insert("params", triggerType.parameters());
triggerTypes.append(triggerMap);
}
QVariantList actionTypes;
foreach (const ActionType &actionType, deviceClass.actions()) {
QVariantMap actionMap;
actionMap.insert("id", actionType.id().toString());
actionMap.insert("name", actionType.name());
actionMap.insert("params", actionType.parameters());
actionTypes.append(actionMap);
}
variant.insert("params", deviceClass.params());
variant.insert("states", stateTypes);
variant.insert("triggers", triggerTypes);
variant.insert("actions", actionTypes);
return variant;
}
QString pluginTypeRef()
{
return "$ref:PluginType";
}
QVariantMap pluginTypeDescription()
{
QVariantMap pluginDescription;
pluginDescription.insert("id", "uuid");
pluginDescription.insert("name", "string");
QVariantList params;
params.append(paramTypeRef());
pluginDescription.insert("params", params);
return pluginDescription;
}
QVariantMap packPlugin(DevicePlugin *plugin)
{
}
QString deviceRef()
{
return "$ref:Device";
}
QVariantMap deviceDescription()
{
QVariantMap deviceDescription;
deviceDescription.insert("id", "uuid");
deviceDescription.insert("deviceClassId", "uuid");
deviceDescription.insert("name", "string");
QVariantList params;
params.append(paramRef());
deviceDescription.insert("params", params);
return deviceDescription;
}
QVariantMap packDevice(Device *device)
{
QVariantMap variant;
variant.insert("id", device->id());
variant.insert("deviceClassId", device->deviceClassId());
variant.insert("name", device->name());
variant.insert("params", device->params());
return variant;
}
bool validateMap(const QVariantMap &templateMap, const QVariantMap &map)
{
foreach (const QString &key, templateMap.keys()) {
if (!map.contains(key)) {
qDebug() << "missing key" << key << templateMap << map;
return false;
}
if (!validateVariant(templateMap.value(key), map.value(key))) {
qDebug() << "Object not matching template";
return false;
}
}
return true;
}
bool validateProperty(const QVariant &templateValue, const QVariant &value)
{
if (templateValue == "uuid") {
return value.canConvert(QVariant::Uuid);
}
if (templateValue == "string") {
return value.canConvert(QVariant::String);
}
if (templateValue == "bool") {
return value.canConvert(QVariant::Bool);
}
qWarning() << "Unhandled property type!" << templateValue;
return false;
}
bool validateList(const QVariantList &templateList, const QVariantList &list)
{
Q_ASSERT(templateList.count() == 1);
QVariant entryTemplate = templateList.first();
qDebug() << "validating list" << templateList;
for (int i = 0; i < list.count(); ++i) {
QVariant listEntry = list.at(i);
if (!validateVariant(entryTemplate, listEntry)) {
qDebug() << "List entry not matching template";
return false;
}
}
return true;
}
bool validateVariant(const QVariant &templateVariant, const QVariant &variant)
{
switch(templateVariant.type()) {
case QVariant::String:
if (templateVariant.toString().startsWith("$ref:")) {
QString refName = templateVariant.toString();
if (refName == JsonTypes::actionRef()) {
qDebug() << "validating action";
if (!validateMap(actionDescription(), variant.toMap())) {
qDebug() << "Error validating action";
return false;
}
} else if (refName == JsonTypes::triggerRef()) {
if (!validateMap(triggerDescription(), variant.toMap())) {
qDebug() << "trigger not valid";
return false;
}
} else if (refName == deviceRef()) {
if (!validateMap(deviceDescription(), variant.toMap())) {
qDebug() << "device not valid";
return false;
}
} else if (refName == deviceClassRef()) {
if (!validateMap(deviceClassDescription(), variant.toMap())) {
qDebug() << "device class not valid";
return false;
}
} else if (refName == paramTypeRef()) {
if (!validateMap(paramTypeDescription(), variant.toMap())) {
qDebug() << "param types not matching";
return false;
}
} else if (refName == actionTypeRef()) {
if (!validateMap(actionTypeDescription(), variant.toMap())) {
qDebug() << "action type not matching";
return false;
}
} else if (refName == triggerTypeRef()) {
if (!validateMap(triggerTypeDescription(), variant.toMap())) {
qDebug() << "trigger type not matching";
return false;
}
} else if (refName == stateTypeRef()) {
if (!validateMap(stateTypeDescription(), variant.toMap())) {
qDebug() << "state type not matching";
return false;
}
} else if (refName == pluginTypeRef()) {
if (!validateMap(pluginTypeDescription(), variant.toMap())) {
qDebug() << "plugin type not matchint";
return false;
}
} else if (refName == basicTypesRef()) {
if (!validateBasicType(variant)) {
qDebug() << "value not allowed in" << basicTypesRef();
return false;
}
} else {
qDebug() << "unhandled ref:" << refName;
return false;
}
} else {
if (!JsonTypes::validateProperty(templateVariant, variant)) {
qDebug() << "property not matching:" << templateVariant << "!=" << variant;
return false;
}
}
break;
case QVariant::Map:
if (!validateMap(templateVariant.toMap(), variant.toMap())) {
return false;
}
break;
case QVariant::List:
if (!validateList(templateVariant.toList(), variant.toList())) {
return false;
}
break;
default:
qDebug() << "unhandled value" << templateVariant;
return false;
}
return true;
}
bool validateBasicType(const QVariant &variant)
{
if (variant.canConvert(QVariant::Uuid)) {
return true;
}
if (variant.canConvert(QVariant::String)) {
return true;
}
if (variant.canConvert(QVariant::Int)) {
return true;
}
if (variant.canConvert(QVariant::Double)) {
return true;
}
if (variant.canConvert(QVariant::Bool)) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,67 @@
#ifndef JSONTYPES_H
#define JSONTYPES_H
#include "deviceclass.h"
#include "trigger.h"
#include "action.h"
#include "actiontype.h"
#include <QObject>
#include <QVariantMap>
class DevicePlugin;
class Device;
namespace JsonTypes
{
QVariantMap allTypes();
QString basicTypesRef();
QVariantList basicTypes();
QString paramTypeRef();
QVariantMap paramTypeDescription();
QString paramRef();
QVariantMap paramDescription();
QString stateTypeRef();
QVariantMap stateTypeDescription();
QString triggerTypeRef();
QVariantMap triggerTypeDescription();
QVariantMap packTriggerType(const TriggerType &triggerType);
QString triggerRef();
QVariantMap triggerDescription();
QVariantMap packTrigger(const Trigger &trigger);
QString actionTypeRef();
QVariantMap actionTypeDescription();
QVariantMap packActionType(const ActionType &actionType);
QString actionRef();
QVariantMap actionDescription();
QVariantMap packAction(const Action &action);
QString deviceClassRef();
QVariantMap deviceClassDescription();
QVariantMap packDeviceClass(const DeviceClass &deviceClass);
QString pluginTypeRef();
QVariantMap pluginTypeDescription();
QVariantMap packPlugin(DevicePlugin *plugin);
QString deviceRef();
QVariantMap deviceDescription();
QVariantMap packDevice(Device *device);
bool validateMap(const QVariantMap &templateMap, const QVariantMap &map);
bool validateProperty(const QVariant &templateValue, const QVariant &value);
bool validateList(const QVariantList &templateList, const QVariantList &list);
bool validateVariant(const QVariant &templateVariant, const QVariant &variant);
bool validateBasicType(const QVariant &variant);
}
#endif // JSONTYPES_H

View File

@ -0,0 +1,99 @@
#include "ruleshandler.h"
#include "hivecore.h"
#include "ruleengine.h"
#include <QDebug>
RulesHandler::RulesHandler(QObject *parent) :
JsonHandler(parent)
{
QVariantMap params;
QVariantMap returns;
params.clear(); returns.clear();
setDescription("GetRules", "Get all configured rules");
setParams("GetRules", params);
setReturns("GetRules", returns);
params.clear(); returns.clear();
setDescription("AddRule", "Add a rule");
params.insert("trigger", JsonTypes::triggerRef());
QVariantList actions;
actions.append(JsonTypes::actionRef());
params.insert("actions", actions);
setParams("AddRule", params);
setReturns("AddRule", returns);
}
QString RulesHandler::name() const
{
return "Rules";
}
QVariantMap RulesHandler::GetRules(const QVariantMap &params)
{
Q_UNUSED(params)
QVariantList rulesList;
foreach (const Rule &rule, HiveCore::instance()->ruleEngine()->rules()) {
qDebug() << "got rule" << rule.id();
QVariantMap ruleMap;
ruleMap.insert("id", rule.id());
ruleMap.insert("trigger", JsonTypes::packTrigger(rule.trigger()));
QVariantList actionList;
foreach (const Action &action, rule.actions()) {
actionList.append(JsonTypes::packAction(action));
}
ruleMap.insert("actions", actionList);
rulesList.append(ruleMap);
}
QVariantMap returns;
returns.insert("rules", rulesList);
return returns;
}
QVariantMap RulesHandler::AddRule(const QVariantMap &params)
{
QVariantMap triggerMap = params.value("trigger").toMap();
QUuid triggerTypeId = triggerMap.value("triggerTypeId").toUuid();
QUuid triggerDeviceId = triggerMap.value("deviceId").toUuid();
QVariantMap triggerParams = triggerMap.value("params").toMap();
Trigger trigger(triggerTypeId, triggerDeviceId, triggerParams);
QList<Action> actions;
QVariantList actionList = params.value("actions").toList();
qDebug() << "got action list" << actionList.count();
foreach (const QVariant &actionVariant, actionList) {
QVariantMap actionMap = actionVariant.toMap();
Action action(actionMap.value("deviceId").toUuid(), actionMap.value("actionTypeId").toUuid());
action.setParams(actionMap.value("params").toMap());
actions.append(action);
}
QVariantMap returns;
if (actions.count() == 0) {
returns.insert("success", false);
returns.insert("errorMessage", "Missing parameter: \"actions\".");
return returns;
}
switch(HiveCore::instance()->ruleEngine()->addRule(trigger, actions)) {
case RuleEngine::RuleErrorNoError:
returns.insert("success", true);
break;
case RuleEngine::RuleErrorDeviceNotFound:
returns.insert("success", false);
returns.insert("errorMessage", "No such device.");
break;
case RuleEngine::RuleErrorTriggerTypeNotFound:
returns.insert("success", false);
returns.insert("errorMessage", "Device does not have such a trigger type.");
break;
}
return returns;
}

View File

@ -0,0 +1,20 @@
#ifndef RULESHANDLER_H
#define RULESHANDLER_H
#include "jsonhandler.h"
class RulesHandler : public JsonHandler
{
Q_OBJECT
public:
explicit RulesHandler(QObject *parent = 0);
QString name() const override;
Q_INVOKABLE QVariantMap GetRules(const QVariantMap &params);
Q_INVOKABLE QVariantMap AddRule(const QVariantMap &params);
};
#endif // RULESHANDLER_H

View File

@ -1,299 +0,0 @@
#include "jsonrpcserver.h"
#include "tcpserver.h"
#include "hivecore.h"
#include "devicemanager.h"
#include "deviceplugin.h"
#include "deviceclass.h"
#include "device.h"
#include "rule.h"
#include "ruleengine.h"
#include <QJsonDocument>
#include <QStringList>
JsonRPCServer::JsonRPCServer(QObject *parent):
QObject(parent),
m_tcpServer(new TcpServer(this))
{
connect(m_tcpServer, &TcpServer::jsonDataAvailable, this, &JsonRPCServer::processData);
m_tcpServer->startServer();
}
void JsonRPCServer::processData(int clientId, const QByteArray &jsonData)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &error);
if(error.error != QJsonParseError::NoError) {
qDebug() << "failed to parse data" << jsonData << ":" << error.errorString();
}
qDebug() << "-------------------------\n" << jsonDoc.toJson();
QVariantMap message = jsonDoc.toVariant().toMap();
bool success;
int commandId = message.value("id").toInt(&success);
if (!success) {
qWarning() << "Error parsing command. Missing \"id\":" << jsonData;
return;
}
QStringList commandList = message.value("method").toString().split('.');
if (commandList.count() != 2) {
qWarning() << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\"";
return;
}
QString targetNamespace = commandList.first();
QString method = commandList.last();
QVariantMap params = message.value("params").toMap();
qDebug() << "got:" << targetNamespace << method << params;
emit commandReceived(targetNamespace, method, params);
if (targetNamespace == "Devices") {
handleDevicesMessage(clientId, commandId, method, params);
} else if (targetNamespace == "Rules") {
handleRulesMessage(clientId, commandId, method, params);
} else if (targetNamespace == "Actions") {
handleActionMessage(clientId, commandId, method, params);
} else {
qDebug() << "got unknown namespace" << targetNamespace;
}
}
void JsonRPCServer::handleDevicesMessage(int clientId, int commandId, const QString &method, const QVariantMap &params)
{
if (method == "GetSupportedDevices") {
QVariantMap params;
QVariantList supportedDeviceList;
foreach (const DeviceClass &deviceClass, HiveCore::instance()->deviceManager()->supportedDevices()) {
supportedDeviceList.append(packDeviceClass(deviceClass));
}
params.insert("deviceClasses", supportedDeviceList);
sendResponse(clientId, commandId, params);
} else if (method == "GetPlugins") {
QVariantMap params;
QVariantList plugins;
foreach (DevicePlugin *plugin, HiveCore::instance()->deviceManager()->plugins()) {
QVariantMap pluginMap;
pluginMap.insert("id", plugin->pluginId());
pluginMap.insert("name", plugin->pluginName());
pluginMap.insert("config", plugin->configuration());
plugins.append(pluginMap);
}
params.insert("plugins", plugins);
sendResponse(clientId, commandId, params);
} else if (method == "SetPluginConfig") {
QUuid pluginId = params.value("pluginId").toUuid();
QVariantMap pluginParams = params.value("params").toMap();
HiveCore::instance()->deviceManager()->plugin(pluginId)->setConfiguration(pluginParams);
sendResponse(clientId, commandId);
} else if (method == "AddConfiguredDevice") {
QUuid deviceClass = params.value("deviceClass").toUuid();
QVariantMap deviceParams = params.value("params").toMap();
DeviceManager::DeviceError status = HiveCore::instance()->deviceManager()->addConfiguredDevice(deviceClass, deviceParams);
switch(status) {
case DeviceManager::DeviceErrorNoError:
sendResponse(clientId, commandId);
break;
case DeviceManager::DeviceErrorDeviceClassNotFound:
sendErrorResponse(clientId, commandId, "Error creating device. Device class not found.");
break;
case DeviceManager::DeviceErrorMissingParameter:
sendErrorResponse(clientId, commandId, "Error creating device. Missing parameter.");
break;
case DeviceManager::DeviceErrorSetupFailed:
sendErrorResponse(clientId, commandId, "Error creating device. Device setup failed.");
break;
default:
sendErrorResponse(clientId, commandId, "Unknown error.");
}
} else if (method == "GetConfiguredDevices") {
QVariantMap rspParams;
QVariantList configuredDeviceList;
foreach (Device *device, HiveCore::instance()->deviceManager()->configuredDevices()) {
configuredDeviceList.append(packDevice(device));
}
rspParams.insert("devices", configuredDeviceList);
sendResponse(clientId, commandId, rspParams);
} else {
sendErrorResponse(clientId, commandId, "No such method");
}
}
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("trigger", packTrigger(rule.trigger()));
QVariantList actionList;
foreach (const Action &action, rule.actions()) {
actionList.append(packAction(action));
}
ruleMap.insert("actions", actionList);
rulesList.append(ruleMap);
}
QVariantMap rspParams;
rspParams.insert("rules", rulesList);
sendResponse(clientId, commandId, rspParams);
} else if (method == "AddRule") {
QVariantMap triggerMap = params.value("trigger").toMap();
QUuid triggerTypeId = triggerMap.value("triggerTypeId").toUuid();
QUuid triggerDeviceId = triggerMap.value("deviceId").toUuid();
QVariantMap triggerParams = triggerMap.value("params").toMap();
Trigger trigger(triggerTypeId, triggerDeviceId, triggerParams);
QList<Action> actions;
QVariantList actionList = params.value("actions").toList();
foreach (const QVariant &actionVariant, actionList) {
QVariantMap actionMap = actionVariant.toMap();
Action action(actionMap.value("deviceId").toString());
action.setName(actionMap.value("name").toString());
action.setParams(actionMap.value("params").toMap());
actions.append(action);
}
if (actions.count() == 0) {
sendErrorResponse(clientId, commandId, "Missing parameter: \"actions\".");
return;
}
switch(HiveCore::instance()->ruleEngine()->addRule(trigger, actions)) {
case RuleEngine::RuleErrorNoError:
sendResponse(clientId, commandId);
break;
case RuleEngine::RuleErrorDeviceNotFound:
sendErrorResponse(clientId, commandId, "No such device.");
break;
case RuleEngine::RuleErrorTriggerTypeNotFound:
sendErrorResponse(clientId, commandId, "Device does not have such a trigger type.");
break;
}
}
}
void JsonRPCServer::handleActionMessage(int clientId, int commandId, const QString &method, const QVariantMap &params)
{
if (method == "ExecuteAction") {
QVariantMap actionMap = params.value("action").toMap();
QUuid deviceId = actionMap.value("deviceId").toUuid();
QVariantMap actionParams = actionMap.value("params").toMap();
Action action(deviceId);
action.setParams(actionParams);
qDebug() << "actions params in json" << action.params();
DeviceManager::DeviceError error = HiveCore::instance()->deviceManager()->executeAction(action);
switch (error) {
case DeviceManager::DeviceErrorNoError:
sendResponse(clientId, commandId);
break;
case DeviceManager::DeviceErrorDeviceNotFound:
sendErrorResponse(clientId, commandId, "No such device");
break;
default:
sendErrorResponse(clientId, commandId, "Unknown error.");
}
}
}
QVariantMap JsonRPCServer::packDeviceClass(const DeviceClass &deviceClass)
{
QVariantMap variant;
variant.insert("name", deviceClass.name());
variant.insert("id", deviceClass.id());
QVariantList stateTypes;
foreach (const StateType &stateType, deviceClass.states()) {
QVariantMap stateMap;
stateMap.insert("id", stateType.id().toString());
stateMap.insert("name", stateType.name());
stateMap.insert("type", QVariant::typeToName(stateType.type()));
stateTypes.append(stateMap);
}
QVariantList triggerTypes;
foreach (const TriggerType &triggerType, deviceClass.triggers()) {
QVariantMap triggerMap;
triggerMap.insert("id", triggerType.id().toString());
triggerMap.insert("name", triggerType.name());
triggerMap.insert("params", triggerType.parameters());
triggerTypes.append(triggerMap);
}
QVariantList actionTypes;
foreach (const ActionType &actionType, deviceClass.actions()) {
QVariantMap actionMap;
actionMap.insert("id", actionType.id().toString());
actionMap.insert("name", actionType.name());
actionMap.insert("params", actionType.parameters());
actionTypes.append(actionMap);
}
variant.insert("params", deviceClass.params());
variant.insert("states", stateTypes);
variant.insert("triggers", triggerTypes);
variant.insert("actions", actionTypes);
return variant;
}
QVariantMap JsonRPCServer::packDevice(Device *device)
{
QVariantMap variant;
variant.insert("id", device->id());
variant.insert("deviceClassId", device->deviceClassId());
variant.insert("name", device->name());
variant.insert("params", device->params());
return variant;
}
QVariantMap JsonRPCServer::packTrigger(const Trigger &trigger)
{
QVariantMap variant;
variant.insert("id", trigger.triggerTypeId());
variant.insert("deviceId", trigger.deviceId());
variant.insert("params", trigger.params());
return variant;
}
QVariantMap JsonRPCServer::packAction(const Action &action)
{
QVariantMap variant;
variant.insert("id", action.id());
variant.insert("deviceId", action.deviceId());
variant.insert("name", action.name());
variant.insert("params", action.params());
return variant;
}
void JsonRPCServer::sendResponse(int clientId, int commandId, const QVariantMap &params)
{
QVariantMap rsp;
rsp.insert("id", commandId);
rsp.insert("status", "success");
rsp.insert("params", params);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(rsp);
m_tcpServer->sendResponse(clientId, jsonDoc.toJson());
}
void JsonRPCServer::sendErrorResponse(int clientId, int commandId, const QString &error)
{
QVariantMap rsp;
rsp.insert("id", commandId);
rsp.insert("status", "error");
rsp.insert("error", error);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(rsp);
m_tcpServer->sendResponse(clientId, jsonDoc.toJson());
}

View File

@ -40,7 +40,6 @@ RuleEngine::RuleEngine(QObject *parent) :
foreach (const QString &actionIdString, settings.childGroups()) {
settings.beginGroup(actionIdString);
Action action = Action(settings.value("deviceId").toUuid(), settings.value("id").toUuid());
action.setName(settings.value("name").toString());
action.setParams(settings.value("params").toMap());
settings.endGroup();
actions.append(action);
@ -136,9 +135,8 @@ RuleEngine::RuleError RuleEngine::addRule(const Trigger &trigger, const QList<St
settings.beginGroup("actions");
foreach (const Action &action, rule.actions()) {
settings.beginGroup(action.id().toString());
settings.beginGroup(action.actionTypeId().toString());
settings.setValue("deviceId", action.deviceId());
settings.setValue("name", action.name());
settings.setValue("params", action.params());
settings.endGroup();
}

View File

@ -1,7 +1,7 @@
TARGET = hive
TEMPLATE = app
INCLUDEPATH += ../libhive
INCLUDEPATH += ../libhive jsonrpc
target.path = /usr/bin
INSTALLS += target
@ -12,17 +12,27 @@ CONFIG += c++11
LIBS += -L../libhive/ -lhive
SOURCES += main.cpp \
hivecore.cpp \
jsonrpcserver.cpp \
tcpserver.cpp \
ruleengine.cpp \
rule.cpp
hivecore.cpp \
tcpserver.cpp \
ruleengine.cpp \
rule.cpp \
jsonrpc/jsonrpcserver.cpp \
jsonrpc/jsonhandler.cpp \
jsonrpc/devicehandler.cpp \
jsonrpc/jsontypes.cpp \
jsonrpc/ruleshandler.cpp \
jsonrpc/actionhandler.cpp
HEADERS += hivecore.h \
jsonrpcserver.h \
tcpserver.h \
ruleengine.h \
rule.h
tcpserver.h \
ruleengine.h \
rule.h \
jsonrpc/jsonrpcserver.h \
jsonrpc/jsonhandler.h \
jsonrpc/devicehandler.h \
jsonrpc/jsontypes.h \
jsonrpc/ruleshandler.h \
jsonrpc/actionhandler.h
# FIXME: Drop this and link them dynamically
LIBS += -L../plugins/deviceplugins/elro/ -lhive_devicepluginelro

View File

@ -10,18 +10,18 @@ elif [ -z $2 ]; then
else
if [ $2 == "elroremote" ]; then
# Adds an ELRO remote control on channel 00000
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClass": "{d85c1ef4-197c-4053-8e40-707aa671d302}","params":{"channel1":"true", "channel2":"false", "channel3":"false", "channel4": "false", "channel5":"false" }}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClassId": "{d85c1ef4-197c-4053-8e40-707aa671d302}","deviceParams":{"channel1":"true", "channel2":"false", "channel3":"false", "channel4": "false", "channel5":"false" }}}'; sleep 1) | nc $1 1234
elif [ $2 == "elroswitch" ]; then
# Adds a ELRO power switch on channel 00000 and group E
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClass": "{308ae6e6-38b3-4b3a-a513-3199da2764f8}","params":{"channel1":"false","channel2":"false", "channel3":"false", "channel4": "false","channel5":"false","A":"false","B":"true","C":"false","D":"false","E":"false" }}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClassId": "{308ae6e6-38b3-4b3a-a513-3199da2764f8}","deviceParams":{"channel1":"false","channel2":"false", "channel3":"false", "channel4": "false","channel5":"false","A":"false","B":"true","C":"false","D":"false","E":"false" }}}'; sleep 1) | nc $1 1234
elif [ $2 == "intertechnoremote" ]; then
# Adds an intertechno remote control
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClass": "{ab73ad2f-6594-45a3-9063-8f72d365c5e5}","params":{"familyCode":"J"}}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClassId": "{ab73ad2f-6594-45a3-9063-8f72d365c5e5}","deviceParams":{"familyCode":"J"}}}'; sleep 1) | nc $1 1234
elif [ $2 == "meisteranker" ]; then
# Adds an intertechno remote control
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClass": "{e37e9f34-95b9-4a22-ae4f-e8b874eec871}","params":{"id":"1"}}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClassId": "{e37e9f34-95b9-4a22-ae4f-e8b874eec871}","deviceParams":{"id":"1"}}}'; sleep 1) | nc $1 1234
elif [ $2 == "wifidetector" ]; then
# Adds a WiFi detector
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClass": "{bd216356-f1ec-4324-9785-6982d2174e17}","params":{"mac":"90:cf:15:1b:ce:bb"}}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Devices.AddConfiguredDevice", "params":{"deviceClassId": "{bd216356-f1ec-4324-9785-6982d2174e17}","deviceParams":{"mac":"90:cf:15:1b:ce:bb"}}}'; sleep 1) | nc $1 1234
fi
fi

View File

@ -1,8 +1,8 @@
#!/bin/bash
if test -z $3; then
echo "usage: $1 host triggerTypeId sourceDeviceId targetDeviceId"
if test -z $5; then
echo "usage: $0 host sourceDevice triggerTypeId targetDeviceId actionTypeId"
else
(echo '{"id":1, "method":"Rules.AddRule", "params":{"trigger": {"triggerTypeId": "'$2'", "deviceId":"'$3'", "params":{"power":"true"}}, "actions": [ { "deviceId":"'$4'", "name":"rule 1", "params":{"power":"true"}}, { "deviceId":"'$5'", "name":"rule 1", "params":{"power":"true"}}]}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Rules.AddRule", "params":{"trigger": {"triggerTypeId": "'$2'", "deviceId":"'$3'", "params":{"power":"false"}}, "actions": [ { "deviceId":"'$4'", "name":"rule 1", "params":{"power":"false"}},{ "deviceId":"'$5'", "name":"rule 1", "params":{"power":"true"}}]}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Rules.AddRule", "params":{"trigger": {"triggerTypeId": "'$3'", "deviceId":"'$2'", "params":{"power":"true"}}, "actions": [ { "deviceId":"'$4'", "actionTypeId":"'$5'", "params":{"power":"true"}}]}}'; sleep 1) | nc $1 1234
# (echo '{"id":1, "method":"Rules.AddRule", "params":{"trigger": {"triggerTypeId": "'$2'", "deviceId":"'$3'", "params":{"power":"false"}}, "actions": [ { "deviceId":"'$4'", "name":"rule 1", "params":{"power":"false"}},{ "deviceId":"'$5'", "name":"rule 1", "params":{"power":"true"}}]}}'; sleep 1) | nc $1 1234
fi

View File

@ -1,7 +1,7 @@
#!/bin/bash
if [ -z $1 ]; then
echo "usage: $0 host deviceId power"
if [ -z $4 ]; then
echo "usage: $0 host actionTypeId deviceId power"
else
(echo '{"id":1, "method":"Actions.ExecuteAction","params":{"action":{"deviceId":"{'$2'}","params":{"power":"'$3'"}}}}'; sleep 1) | nc $1 1234
(echo '{"id":1, "method":"Actions.ExecuteAction","params":{"actionTypeId": "{'$2'}", "deviceId":"{'$3'}","params":{"power":"'$4'"}}}'; sleep 1) | nc $1 1234
fi

7
tests/getactiontypes.sh Executable file
View File

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

7
tests/gettriggertypes.sh Executable file
View File

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

7
tests/introspect.sh Executable file
View File

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